Objektorientierung GrundlagenObjektorientierung Grundlagen › cms › de › pws › haas ›...

246
Objektorientierung Grundlagen Objektorientierung Grundlagen mit der Programmiersprache C++

Transcript of Objektorientierung GrundlagenObjektorientierung Grundlagen › cms › de › pws › haas ›...

  • Objektorientierung GrundlagenObjektorientierung Grundlagen

    mit der Programmiersprache C++

  • OrganisatorischesOrganisatorisches● Veranstaltungen

    – 2 SWS Vorlesung: Mo, 12.00 Uhr, HS A– 2 SWS Hörsaal-Übung: Do, 08.00 Uhr, A245, ab 16.03.2017– 2 SWS studentisches Tutorium: Di, 16.00 Uhr, P7, ab 14.03.2017

    (Betreuer: Nico Schmidt)

    Prof. Dr. Andreas Simon 2Einleitung

  • InhaltInhalt● Kennenlernen der Programmiersprache C++

    – Unterschiede zu Java, wie wir es bisher kennengelernt haben.● Objektorientierung

    – Klassen und Objekte– Objekterzeugung, ObjektfreigabeObjekterzeugung, Objektfreigabe– statische, nicht statische Methoden– Vererbung

    Prof. Dr. Andreas Simon 3Einleitung

  • LiteraturLiteratur1. Jürgen Wolf: Grundkurs C++, Galileo Computing, ISBN 978-3836222945,

    2013, 9,90 €2 S b ti B E li fü C/C P i ISBN 9782. Sebastian Bauer: Eclipse für C/C++-Programmierer, ISBN 978-

    3898647151, Dpunkt Verlag, 2010, 39,90 €3. Arnold Willemer: C++. Der Einstieg, Wiley-VCH Verlag, ISBN 978-

    €3527760442, 2013, 24,99 €4. Jürgen Wolf: C++: Das umfassende Handbuch, Galileo Computing, ISBN

    978-3836220217, 2014, 39,90 €

    Prof. Dr. Andreas Simon 4Einleitung

  • 1. Einleitung1. Einleitung● Standardisierung von C++

    – C++ ist ein Industriestandard nach ISO-Norm (ISO/IEC 14882)– Die zurzeit noch gängigste C++-Variante ist C++03.– Nachfolger von C++03 ist C++11– C++03 ist in C++11 enthalten.C 03 ist in C 11 enthalten.– Aktuelle Version: C++17 ISO/IEC 14882:2017– Alle in dieser Lehrveranstaltung behandelten Themen werden durch

    den Standard C++11 abgedecktden Standard C++11 abgedeckt.

    ● Programmiersprache C– C ist grundsätzlich eine Teilmenge von C++.– C ist nicht objektorientiert.– C ist häufig bei Embedded-Systemen (Micro-Controllern) anzutreffen, bei

    Prof. Dr. Andreas Simon

    C ist häufig bei Embedded Systemen (Micro Controllern) anzutreffen, bei denen kein C++-Compiler zur Verfügung steht.

    5Einführung

  • 1. Einleitung1. Einleitung● Unterschiede zwischen Java und C++

    – C++ ermöglicht direkte Zugriffe auf die Rechnerhardware und ist damit i i i ll l ttf bhä iprinzipiell plattformabhängig.

    – In gutem C++-Programmcode werden plattformabhängige von plattformunabhängigen Modulen getrennt ( Codewiederverwendung).

    – Die Speicherfreigabe erfolgt stets manuell. (Kein Garbage-Collector)– In C++ muss nicht alles in Klassen verpackt werden. (Beispiel: main())– C++ zwingt den Programmierer nicht zur sauberen ProgrammierungC zwingt den Programmierer nicht zur sauberen Programmierung

    (Disziplin erforderlich!).– C++ ist schneller als Java.

    Java ist selbst in C++ geschrieben– Java ist selbst in C++ geschrieben.– C++ ist nach ISO genormt. Java hingegen ist ein Produkt der Firma

    Oracle (früher Sun).

    Prof. Dr. Andreas Simon 6Einleitung

  • 1. Einleitung1. Einleitung● Entwicklungsumgebung

    – Wir verwenden Visual Studio 2015 (RZ-Version).– Bezug: kostenlos für Studierende über das Rechenzentrum – Visual Studio 2015 Express: Für alle kostenlos von der Microsoft-

    Homepage herunterladbar: https://www.visualstudio.com/de/vs/visual-studio-express/

    – Nicht-Windows-Nutzer können alternativ Eclipse mit dem gcc-CompilerNicht Windows Nutzer können alternativ Eclipse mit dem gcc Compiler verwenden.

    Achtung: Die Klausur wird unter Visual Studio 2015 geschrieben!– Achtung: Die Klausur wird unter Visual Studio 2015 geschrieben!

    Prof. Dr. Andreas Simon 7EinführungVisual Studio

  • 1.1 Visual Studio1.1 Visual Studio● Visual Studio Community von https://www.visualstudio.com herunterladen

    und installieren:

    Bitte auch auswählen

    Prof. Dr. Andreas Simon 8EinführungVisual Studio

  • 1.1 Visual Studio1.1 Visual Studio● Visual Studio Community von https://www.visualstudio.com herunterladen

    und installieren:

    Prof. Dr. Andreas Simon 9EinführungVisual Studio

  • 1.1 Visual Studio1.1 Visual Studio● Öffnen von VS 2015-Projekten durch VS 2017

    – Inkompatibilitäten können meistens durch die Anpassung des Pl ttf t l t d d Wi d SDK V i b h b dPlattformtoolsets oder der Windows SDK-Version behoben werden:

    Prof. Dr. Andreas Simon 10EinführungVisual Studio

  • 1.1 Visual Studio1.1 Visual Studio● Visual Studio starten:

    ggf. C++ nachinstallieren

    Visual Studio starten

    gg

    Prof. Dr. Andreas Simon 11EinführungVisual Studio

  • 1.1 Visual Studio1.1 Visual Studio● Visual Studio starten:

    C++ auswählenC++ auswählen

    Prof. Dr. Andreas Simon 12EinführungVisual Studio

  • 1.1 Visual Studio1.1 Visual Studio● Erstes Programm "Hello World"

    Prof. Dr. Andreas Simon 13EinführungVisual Studio

  • 1.1 Visual Studio1.1 Visual Studio● Erstes Programm "Hello World"

    Prof. Dr. Andreas Simon 14EinführungVisual Studio

  • 1.1 Visual Studio1.1 Visual Studio● Erstes Programm "Hello World"

    Prof. Dr. Andreas Simon 15EinführungVisual Studio

  • 1.1 Visual Studio1.1 Visual Studio● Erstes Programm "Hello World"

    Prof. Dr. Andreas Simon 16EinführungVisual Studio

  • 1.1 Visual Studio1.1 Visual Studio● Erstes Programm "Hello World"

    Prof. Dr. Andreas Simon 17EinführungVisual Studio

  • 1.2 Eclipse1.2 Eclipse● Entwicklungsumgebung Eclipse

    – Für Nicht-Windows-Nutzer wird für zu Hause Eclipse mit dem Compiler Mi GW f hlMinGW empfohlen.

    – Exkurs:○ MinGW = Windowsvariante von GCC○ GCC = GNU Compiler Collection○ GNU = „GNU is Not Unix“ (unixähnliches Betriebssystem, quelloffen)Im Rechenzentrum ist Eclipse für C++ eingerichtet– Im Rechenzentrum ist Eclipse für C++ eingerichtet.

    – Anleitung zur Installation auf dem privaten Rechner befindet sich im Stud.IP-Bereich.

    Prof. Dr. Andreas Simon 18EinführungEcplise

  • 1.2 Eclipse1.2 Eclipse

    Prof. Dr. Andreas Simon 19C++-GrundlagenEclipse

  • 1.2 Konsolen Ein-/Ausgabe1.2 Konsolen Ein /Ausgabe● Hello-World-Beispiel

    // Datei: main.cpp (Endung .cpp = C++)// Datei: main.cpp (Endung .cpp = C++)// Datei: main.cpp (Endung .cpp  C++)

    #include // ähnlich wie import bei Java// (für std::cout, std::endl)

    // Datei: main.cpp (Endung .cpp  C++)

    #include // ähnlich wie import bei Java// (für std::cout, std::endl)

    int main(int argc, char **argv) // analog zu Java: String[] args{

    std::cout

  • 1.2.1 Einfache Bildschirmausgabe1.2.1 Einfache Bildschirmausgabe● std::cout

    – Syntax:t t i / i bl t i / i blcout

  • 1.2.1 Einfache Bildschirmausgabe1.2.1 Einfache Bildschirmausgabe● std::cout

    – Weitere Beispiele:

    int alter = 56; double gewicht = 71.5; char zeichen = 'A'; 

    int alter = 56; double gewicht = 71.5; char zeichen = 'A'; std::cout

  • 1.2.2 Tastatureingabe1.2.2 Tastatureingabe● Prinzip

    – Anstelle des Output-Streams std::cout wird zum Einlesen der Tastatur d I t St td i d tder Input-Stream std::cin verwendet.

    – An die Stelle des Ausgabeoperators >.– Header-Datei: iostream– Beispiel:

    int i;std::cout

  • 1.3 Schlüsselwörter von C++, C und Java1.3 Schlüsselwörter von C , C und Java● C++,C und Java:

    break case char const continue default do double else enumfor goto if int long return short static switch void volatilefor goto if int long return short static switch void volatile while

    ● nur C++ und C:auto extern register signed sizeof struct typedef unionauto extern register signed sizeof struct typedef union unsigned

    ● nur C++ und Java:t h l f l i t t t d bli thi thcatch class false new private protected public this throw 

    true try ● nur C++:

    b l t t d l t d i t li it f i dasm bool const_cast delete dynamic_cast explicit friendinline mutable namespace operator reinterpret_caststatic_cast template typeid typename using virtual wchar_t

    Prof. Dr. Andreas Simon 24C++-GrundlagenSchlüsselwörter

  • 1.4.1 Grunddatentypen1.4.1 Grunddatentypen

    C++ Java

    ● Vergleich von C++ mit Java

    signed char byte

    unsigned short int char

    signed short int short

    signed int int

    signed long int intg g

    signed long long int long

    float float

    double double

    bool boolean

    Prof. Dr. Andreas SimonC++-GrundlagenDatentypen 25

  • 1.4.1 Grunddatentypen1.4.1 GrunddatentypenDatentyp Wertebereich #Bitssigned char -128…127 8unsigned char 0…255 8signed short int -32 768 ... 32 767 16

    i d h t i t 0 65 535 16unsigned short int 0 ... 65 535 16signed intsigned long int

    -2 147 483 648 ... 2 147 483 647 32

    unsigned intunsigned long int

    0 ... 4 294 967 295 (4.2E+9) 32

    signed long long int -9.2E+18 … 9 2E+18 64unsigned long long int 0…1.8E+19 64float ca. 3.4E-38 ... 3.4E+38 (7 digits) 32double ca 1 7E 308 1 7E+308 (15 digits) 64

    Prof. Dr. Andreas SimonC++-Grundlagen Datentypen 26

    double ca. 1.7E-308 ... 1.7E+308 (15 digits) 64bool true, false 8

  • 1.4.1 Grunddatentypen1.4.1 Grunddatentypen● Besonderheiten im Umgang mit Variablen

    – Variableninitialisierung○ Variablen werden nicht automatisch initialisiert.○ Nicht initialisierte Variablen enthalten undefinierte Werte.○ Auf nicht initialisierte Variablen darf (sollte aber nicht) lesendAuf nicht initialisierte Variablen darf (sollte aber nicht) lesend

    zugegriffen werden.– Type-Casts○ Auch ohne expliziten Type Cast lassen sich viele Grunddatentypen○ Auch ohne expliziten Type-Cast lassen sich viele Grunddatentypen

    mischen.○ Der Programmierer bekommt bei drohendem Datenverlust im besten

    Fall eine Warnung vom CompilerFall eine Warnung vom Compiler.

    Prof. Dr. Andreas Simon 27C++-GrundlagenDatentypen

  • b● Zuweisungskompatibilität

    b

    unc c

    uns s

    un unl l

    unlon

    lon f do

    rechter Wert b (R-value)a=b;

    bool

    signedchar

    char

    signedshort

    short

    sighedint

    int

    signedlong

    long

    signedng

    long

    nglong

    float

    ouble

    bool

    unsigned char

    char

    unsigned short

    h ta (L

    -val

    ue)

    möglicherDatenverlust mit

    Compiler Warnung

    1.4.1 Grunddatentypen

    short

    unsigned int

    int

    unsigned longnker

    Wer

    t a Compiler-Warnung

    möglicherDatenverlust ohneunsigned long

    long

    unsigned long long

    long long

    lin

    kein

    Datenverlust ohneCompiler-Warnung

    Prof. Dr. Andreas Simon 28C++-GrundlagenDatentypen

    float

    double

    keinDatenverlust

  • 1.4.1 Grunddatentypen1.4.1 Grunddatentypen● Ergebnistypen von arithmetischen Ausdrücken

    – Wie bei Java gilt auch bei C++ der Grundsatz: der umfassendere (b it ) D t t t t i h d h(breitere) Datentyp setzt sich durch.

    – Beispiel: double + int double● Implizite Typumwandlungen

    – Sind Typumwandlungen erforderlich und ohne Datenverlust möglich, werden sie vom Compiler i. Allg. automatisch vorgenommen.

    ● Explizite Typumwandlungen● Explizite Typumwandlungen– Sind bei Typumwandlungen Datenverluste möglich, warnt der Compiler

    zwar, übersetzt jedoch i.Allg. trotzdem den Quellcode! Explizite Typumwandlungen werden durch– Explizite Typumwandlungen werden durch static_cast(Ausdruck) umgesetzt.

    – Die Java-Variante (Typ)(Ausdruck) ist auch möglich, sollte aber nur in begründeten Ausnahmefällen eingesetzt werden

    Prof. Dr. Andreas Simon

    begründeten Ausnahmefällen eingesetzt werden.

    29C++-GrundlagenDatentypen

  • 1.4.1 Grunddatentypen1.4.1 Grunddatentypen● ImpliziteTypumwandlung

    – Ergebnistypen von arithmetischen Ausdrücken: a b– Ergebnistyp der Operanden richtet sich nach Reihenfolge der

    Typumwandlung (leicht vereinfacht):1. einer long double beide long double2. einer double beide double3. einer float beide float4. einer unsigned long beide unsigned long5. einer long beide long6 einer unsigned beide unsigned6. einer unsigned beide unsigned7. beide sind int

    Prof. Dr. Andreas Simon 30C++-GrundlagenDatentypen

  • 1.4.1 Grunddatentypen1.4.1 Grunddatentypen● Datentyp bool

    – Der Datentyp bool entspricht dem Java-Datentyp boolean.– Eine bool‘sche Variable kann nur die beiden Werte true und false

    annehmen.– In C++ wird bool intern als ganzzahliger Datentyp verwendet.– Intern bedeuten false:0 und true: 1.– Versucht man, einer bool‘sche Variable eine Zahl ungleich null

    zuzuweisen, bekommt die Variable den Wert 1 zugewiesen. Zusätzlichzuzuweisen, bekommt die Variable den Wert 1 zugewiesen. Zusätzlich gibt es eine Warnung vom Compiler.

    – Genau wie in Java* sollte man es unbedingt vermeiden:○ bool‘schen Variablen Zahlen zuzuweisen○ bool schen Variablen Zahlen zuzuweisen○ Integer-Variablen bool‘sche Werte zuzuweisen

    Prof. Dr. Andreas Simon 31C++-GrundlagenGrunddatentypenbool

    *In Java würde man einen Compilerfehler erhalten.

  • 1.4.1 Grunddatentypen1.4.1 Grunddatentypen● Datentyp bool

    – Beispiele:

    bool b = true;cout

  • 1.4.1 Grunddatentypen1.4.1 Grunddatentypen● Operatoren (AND, OR, XOR, NOT)● Rückblick (Java):

    – Die Operatoren AND, OR, XOR, NOT können in Java Variablen logischoder bitweise verknüpfen / modifizieren.

    – Dies hängt in Java von den verwendeten Datentypen ab:boolean & boolean boolean (logisches UND)int & int int (bitweises UND)

    ● Neu (C++):( )– In C++ kann man bool‘sche Variablen und Integer-Variablen sowohl

    logisch als auch bitweise verknüpfen. (Nachteil ggü. Java!)– Logische Operatoren in C++: && || !Logische Operatoren in C++: && || !– Bitweise Operatoren in C++: & | ^

    Prof. Dr. Andreas Simon 33C++-GrundlagenGrunddatentypenlogische Operatoren

  • 1.4.1 Grunddatentypen1.4.1 Grunddatentypen● Operatoren (AND, OR, XOR, NOT)

    – Anwendung der logischen Operatoren && || ! auf bool‘sche Werte:

    false && false falsetrue && false falsefalse && true false

    false && false falsetrue && false falsefalse && true falseUNDtrue && true truetrue && true true

    false || false falsetrue || false truefalse || false falsetrue || false truetrue || false truefalse || true truetrue || true true

    true || false truefalse || true truetrue || true true

    ODER

    !false true!true false!false true!true falseNICHT

    Prof. Dr. Andreas Simon 34C++-GrundlagenGrunddatentypenlogische Operatoren

  • 1.4.1 Grunddatentypen1.4.1 Grunddatentypen● Operatoren (AND, OR, XOR, NOT)

    – Anwendung der bitweisen Operatoren & | ^ auf bool‘sche Werte:

    false & false 0true & false 0false & true 0

    false & false 0true & false 0false & true 0UNDtrue & true 1true & true 1

    false | false 0true | false 1false | false 0true | false 1true | false 1false | true 1true | true 1

    true | false 1false | true 1true | true 1

    ODER

    XORfalse ^ false 0true ^ false 1false ^ true 1true ^ true 0

    false ^ false 0true ^ false 1false ^ true 1true ^ true 0

    Prof. Dr. Andreas Simon 35C++-GrundlagenGrunddatentypenlogische Operatoren

    true ^ true 0true ^ true 0

  • 1.4.1 Grunddatentypen1.4.1 Grunddatentypen● Operatoren (AND, OR, XOR, NOT)

    – Anwendung der bitweisen Operatoren & | ^ auf Integer-Werte:

    UND3 &  3  312 &  3  03 & 12  0

    3 &  3  312 &  3  03 & 12  012 & 12  1212 & 12  12

    3 |  3  312 | 3 153 |  3  312 | 3 15ODER 12 |  3  153 | 12  1512 | 12  12

    12 |  3  153 | 12  1512 | 12  12

    XOR3 ^  3  012 ^  3  153 ^ 12  1512 ^ 12 0

    3 ^  3  012 ^  3  153 ^ 12  1512 ^ 12 0

    Prof. Dr. Andreas Simon 36C++-GrundlagenGrunddatentypenlogische Operatoren

    12 ^ 12  012 ^ 12  0

  • 1.4.1 Grunddatentypen1.4.1 Grunddatentypen● Operatoren (AND, OR, XOR, NOT)

    – Anwendung der logischen Operatoren && || ! auf Integer-Werte:

    UND3 &&  3  112 &&  3  1 3 && 12  1 

    3 &&  3  112 &&  3  1 3 && 12  1 12 && 12  1 12 && 12  1 

    3 ||  3  112 || 3 13 ||  3  112 || 3 1ODER 12 ||  3  1 3 || 12  1 12 || 12  1 

    12 ||  3  1 3 || 12  1 12 || 12  1 

    NICHT! 3  0 !12  0! 3  0 !12  0

    Prof. Dr. Andreas Simon 37C++-GrundlagenGrunddatentypenlogische Operatoren

  • 1.4.2 Typdefinition1.4.2 Typdefinition● 1.4.2 Eigene Datentypen definieren

    – Die ganzzahligen Datentypen sind bei machen Compilern auch l ttf bhä i B i i l i f t d D t t i t b i iplattformabhängig. Beispielsweise umfasst der Datentyp int bei einem

    16-Bit-Microcontroller i. Allg. auch nur 16 bit.– Dies stellt einen deutlichen Nachteil gegenüber Java dar.– Lösung: Durch Verwendung eigener Datentypen kann hierbei eine

    Eindeutigkeit hergestellt werden.– Eigene Datentyp können mit der Anweisung typedef definiert werden.g yp g yp– Beispiel:

    typedef int sint32; // neuer Datentyp sint32 (sint32 wie int)typedef int sint32; // neuer Datentyp sint32 (sint32 wie int)

    – Merke: Typen werden wie Variablen definiert: links steht der bekannte

    sint32 variable = ‐3;sint32 variable = ‐3;

    Prof. Dr. Andreas Simon

    Datentyp.

    38C++-GrundlagenDatentypen

  • 1.4.2 Typdefinition1.4.2 Typdefinition● Eigene Datentypen definieren

    – Für die Sichtbarkeit (scope) von neuen Typen gilt das Gleiche wie für die Si htb k it V i blSichtbarkeit von Variablen.

    – Beispiel:

    typedef int sint32; // neuer Datentyp sint32typedef int sint32; // neuer Datentyp sint32typedef int sint32; // neuer Datentyp sint32

    void methode(){

    typedef int sint32; // neuer Datentyp sint32

    void methode(){

    typedef unsigned int uint32; // neuer Datentyp uint32uint32 ui=2;

    }

    typedef unsigned int uint32; // neuer Datentyp uint32uint32 ui=2;

    }

    sint32 si=‐3;uint32 ui2=2; // Fehler: uint32 nicht bekannt !!sint32 si=‐3;uint32 ui2=2; // Fehler: uint32 nicht bekannt !!

    Prof. Dr. Andreas Simon 39C++-GrundlagenDatentypen

  • 1.4.2 Typdefinition1.4.2 Typdefinition● Eigene Datentypen definieren

    – Es gehört zum guten Programmierstil unter C++, eigene (eindeutige) G dd t t dGrunddatentypen zu verwenden.

    – Die eigenen Grunddatentypen sollten unbedingt nur an einer Stelle im Programm (gesammelt) definiert werden.

    – Dies geschieht am besten in einer separaten Datei, die dann überall nur eingebunden wird ( Header-Datei, s.u.)

    Prof. Dr. Andreas Simon 40C++-GrundlagenDatentypen

  • 1.4.3 Konstanten1.4.3 Konstanten● Typisierte Konstanten

    – In Java werden Konstanten durch final deklariert. In C++ gibt es hierzu d S hlü l ö t t d tdas Schlüsselwörter const und constexpr.

    – Syntax:○  const =< Literal, const. expression, Variable,

    Konstante>;○  constexpr  = ;

    – Beispiel:Beispiel:○ double constexpr PI = 3.142; ○ double const ANZAHL = i; 

    t( ) b i ht i h f di li k S it f di h d– const(expr) bezieht sich auf die linke Seite, sofern diese vorhanden ist, sonst auf die rechte Seite.

    – Auch möglich (sogar üblicher):

    Prof. Dr. Andreas Simon

    ○ constexpr double PI = 3.142; ○ const double ANZAHL = i; 

    41C++-GrundlagenDatentypenKonstanten

  • 1.4.3 Konstanten1.4.3 Konstanten● Typisierte Konstanten

    – Konstantennamen werden in Großbuchstaben geschrieben.– Unterstriche sind üblich, um Wortteile zu trennen.– Beispiel: ANZAHL_SCHUHE– Anwendung:Anwendung:○ const. Expressions werden bereits zur Compilierzeit initialisiert.○ const. Expressions können (anders als normale Konstante) dort

    eingesetzt werden wo bereits zur Compilierzeit die Konstanteeingesetzt werden, wo bereits zur Compilierzeit die Konstante initialisiert sein muss. Z.B. Größen nicht-dynamischer Arrays (s.u.).

    ○ const. Expressions sind normalen Konstanten immer vorzuziehen!vorzuziehen!

    Prof. Dr. Andreas Simon 42C++-GrundlagenDatentypenKonstanten

  • 1.4.4 Aufzählungstypen1.4.4 Aufzählungstypen● Aufzählungstypen

    – Prinzip○ Aufzählungstypen sind spezielle ganzzahlige Datentypen, bei denen

    nur eine bestimmte Menge von Werten zulässig sind.○ Diese Werte sind (wie typisierte Konstanten) mit Bezeichnern

    versehen.– Deklaration

    enum {Werteliste};                       // unüblich{ }enum {Werteliste} variablenname; // unüblichenum Typname {Werteliste};  // üblichenum Typname {Werteliste} variablenname; // üblich

    – Werteliste:{wert1, wert2, wert3, wert4, }{wert1=index1, wert2, wert3, }

    Prof. Dr. Andreas Simon

    {wert1=index1, wert2=index2, } 

    43C++-GrundlagenDatentypenAufzählungstypen

  • 1.4.4 Aufzählungstypen1.4.4 Aufzählungstypen● Beispiele für Aufzählungstypen

    – enum {Werteliste};// Definiton von ganzahligen Konstanten:enum {sonntag,montag,dienstag,mittwoch,donnerstag,freitag,samstag};int heute = sonntag; // heute=0

    // Definiton von ganzahligen Konstanten:enum {sonntag,montag,dienstag,mittwoch,donnerstag,freitag,samstag};int heute = sonntag; // heute=0

    – enum {Werteliste} variablenname;

    // Definiton einer Variable eines Aufzählungsdatentyps// (ohne den Datentyp zu definieren):enum {sonntag,montag,dienstag,mittwoch,donnerstag,freitag,samstag} morgen; morgen = montag;

    // Definiton einer Variable eines Aufzählungsdatentyps// (ohne den Datentyp zu definieren):enum {sonntag,montag,dienstag,mittwoch,donnerstag,freitag,samstag} morgen; morgen = montag;g g;// morgen = 0; // Fehler!// Nutzung der ganzzahligen Konstanten eines Aufzählungsdatentyps:int heute = sonntag;

    g g;// morgen = 0; // Fehler!// Nutzung der ganzzahligen Konstanten eines Aufzählungsdatentyps:int heute = sonntag;

    Prof. Dr. Andreas Simon 44C++-GrundlagenDatentypenAufzählungstypen

  • 1.4.4 Aufzählungstypen1.4.4 Aufzählungstypen● Beispiele für Aufzählungstypen

    – enum Typname {Werteliste};

    // Definiton eines Aufzählungsdatentyps:enum Wochentag{sonntag,montag,dienstag,mittwoch,donnerstag,freitag,samstag};// Definiton einer Variable eines Aufzählungsdatentyps:Wochentag morgen = montag;

    // Definiton eines Aufzählungsdatentyps:enum Wochentag{sonntag,montag,dienstag,mittwoch,donnerstag,freitag,samstag};// Definiton einer Variable eines Aufzählungsdatentyps:Wochentag morgen = montag;Wochentag morgen = montag;// morgen = 0; // Fehler!// Nutzung der ganzzahligen Konstanten eines Aufzählungsdatentyps:int heute = sonntag;// heute=0

    Wochentag morgen = montag;// morgen = 0; // Fehler!// Nutzung der ganzzahligen Konstanten eines Aufzählungsdatentyps:int heute = sonntag;// heute=0

    – enum Typname {Werteliste} variablenname;// Definiton eines Aufzählungsdatentyps (inkl. Definition einer Variablen):enum Wochentag {sonntag,montag,dienstag,mittwoch,donnerstag,freitag, // Definiton eines Aufzählungsdatentyps (inkl. Definition einer Variablen):enum Wochentag {sonntag,montag,dienstag,mittwoch,donnerstag,freitag, g { g, g, g, , g, g,samstag} morgen; morgen = montag;// morgen = 0; // Fehler!// Weitere Variable des Aufzählungsdatentyps definieren:

    g { g, g, g, , g, g,samstag} morgen; morgen = montag;// morgen = 0; // Fehler!// Weitere Variable des Aufzählungsdatentyps definieren:

    Prof. Dr. Andreas Simon 45C++-GrundlagenDatentypenAufzählungstypen

    // g ypWochentag heute = sonntag;// heute = 0; // Fehler!

    // g ypWochentag heute = sonntag;// heute = 0; // Fehler!

  • 1.4.4 Aufzählungstypen1.4.4 Aufzählungstypen● Besonderheiten bei Aufzählungstypen

    – Die Konstanten von Aufzählungstypen werden beginnend mit null jeweils i h h ähltum eins hochgezählt.

    – Der Startwert kann jedoch auch frei vorgegeben werden:

    enum Wochentag {sonntag=1 montag dienstag mittwoch donnerstagenum Wochentag {sonntag=1 montag dienstag mittwoch donnerstag

    Es ist auch möglich die Konstanten individuell zu initialisieren:

    enum Wochentag {sonntag=1, montag, dienstag, mittwoch, donnerstag, freitag, samstag};enum Wochentag {sonntag=1, montag, dienstag, mittwoch, donnerstag, freitag, samstag};

    – Es ist auch möglich, die Konstanten individuell zu initialisieren:

    enum Farbe {kreuz=4, pik=3, herz=2, karo=1};enum Farbe {kreuz=4, pik=3, herz=2, karo=1};

    – Die enum-Deklaration in C++ beinhaltet einen typedef (im Unterschied zu C).

    – Für die Sichtbarkeit von enum-Typen gilt das Gleiche wie für Variablen.

    Prof. Dr. Andreas Simon 46C++-GrundlagenDatentypenAufzählungstypen

  • 1.4.5 Größenabfrage1.4.5 Größenabfrage● sizeof

    – Liefert die Größe eines Datenobjektes in Bytes.– Syntax:○ size_t sizeof() *1)

    ○ size t sizeof *1)_– Beispiel:

    int feld [] = {‐1,2,5}; i t 1 i f f ld // 12(3*4)

    int feld [] = {‐1,2,5}; i t 1 i f f ld // 12(3*4)size_t groesse1 = sizeof feld; // == 12(3*4) 

    int groesse2 = (int)(sizeof(int)); // == 4 unsigned int groesse3 = sizeof groesse2; // == 4

    size_t groesse1 = sizeof feld; // == 12(3*4) int groesse2 = (int)(sizeof(int)); // == 4 unsigned int groesse3 = sizeof groesse2; // == 4

    *1) typedef unsigned int size_t

    Prof. Dr. Andreas Simon 47C++-GrundlagenDatentypen

  • 1.4.6 Strings1.4.6 Strings● Eigenschaften

    – Für Strings steht in C++ die Klasse std::string zur Verfügung.– std::string ist hinsichtlich des Speicherzugriffs im Vergleich zu C-

    Strings sicher.– std::string bietet zahlreiche Methoden zur String-Manipulation.– Speicher wird dynamisch in ausreichender Menge beschafft.– string benötigt die Include-Anweisung:

    #include using namespace std; #include using namespace std; 

    Prof. Dr. Andreas Simon 48C++-GrundlagenDatentypenStrings

  • 1.4.6 Strings1.4.6 Strings

    #include #include

    // D kl ti d I iti li i// D kl ti d I iti li i

    #include using namespace std;#include using namespace std;

    // Deklaration und Initialisierung:string name = "Horst";// Bildschirmausgabe:cout

  • 1.4.6 Strings1.4.6 Strings● Strings über die Tastatur einlesen

    #include #include

    string name; //< leerer Stringstring name; //< leerer String

    #include using namespace std;#include using namespace std;

    getline(cin, name); //< liest ganze Zeile eingetline(cin, name); //< liest ganze Zeile ein

    string name;        //

  • 1.4.6 Strings1.4.6 Strings● Methoden

    – Es stehen mehr als 50 String-Methoden aus den Bereichen○ Erzeugung, Größenänderung, Typumwandlung○ Zuweisen und Anhängen○ EinfügenEinfügen○ Löschen, Ersetzen○ Suchen, Finden

    S b t i V l i h○ Substrings, Vergleiche– zur Verfügung.– Eine Übersicht gibt: http://en.cppreference.com/w/cpp/string/basic_string

    Prof. Dr. Andreas Simon 51C++-GrundlagenDatentypenStrings

  • 1.4.6 Strings1.4.6 Strings● Grunddatentypen in Strings konvertieren

    – Folgende Funktionen konvertieren wichtige Grunddatentypen in Strings:

    #include

    std::string to_string( int value );

    #include

    std::string to_string( int value );std::string to_string( long value );std::string to_string( long long value );std::string to_string( unsigned int value );std::string to string( unsigned long value );

    std::string to_string( long value );std::string to_string( long long value );std::string to_string( unsigned int value );std::string to string( unsigned long value );std::string to_string( unsigned long value );std::string to_string( unsigned long long value );std::string to_string( float value );std::string to_string( double value );

    std::string to_string( unsigned long value );std::string to_string( unsigned long long value );std::string to_string( float value );std::string to_string( double value );std::string to_string( long double value );std::string to_string( long double value );

    Prof. Dr. Andreas Simon 52C++-GrundlagenDatentypenStrings

  • 1.4.6 Strings1.4.6 Strings● Strings in Grunddatentypen konvertieren

    – Folgende Funktionen nehmen wichtige numerische Umwandlungen von St i i G dd t tStrings in Grunddatentypen vor:

    #include using namespace std;#include using namespace std;

    long stol (const string& str, size_t* pos=0, int base=10);int stoi (const string& str, size_t* pos=0, int base=0);long long stoll(const string& str size t* pos=0 int base=10);

    long stol (const string& str, size_t* pos=0, int base=10);int stoi (const string& str, size_t* pos=0, int base=0);long long stoll(const string& str size t* pos=0 int base=10);long long stoll(const string& str, size_t  pos=0, int base=10);

    unsigned long stoul(const string& str, size_t* pos=0, int base=10);unsigned long long stoull(const string& str, size_t* pos=0, int base=10);

    long long stoll(const string& str, size_t  pos=0, int base=10);

    unsigned long stoul(const string& str, size_t* pos=0, int base=10);unsigned long long stoull(const string& str, size_t* pos=0, int base=10);

    float stof (const string& str, size_t* pos=0);double stod (const string& str, size_t* pos=0);long double stold(const string& str size t* pos=0);

    float stof (const string& str, size_t* pos=0);double stod (const string& str, size_t* pos=0);long double stold(const string& str size t* pos=0);

    Prof. Dr. Andreas Simon 53C++-GrundlagenDatentypenStrings

    long double stold(const string& str, size_t  pos=0);long double stold(const string& str, size_t  pos=0);

  • 1.4.6 Strings1.4.6 Strings● Strings in Grunddatentypen konvertieren

    – Achtung: Schlägt eine Umwandlung fehl, wird eine Exception geworfen.– Die einfachste Form, Exceptions und damit diesen Fehler abzufangen

    lässt sich folgendermaßen realisieren:trytryy{

    double pi = stod("3.1415"); // Kann fehlschlagen!cout

  • 1.4.6 Strings1.4.6 Strings● Mit dem Stream-Operator in Strings schreiben

    – In C++ kann man in einen (speziellen) String schreiben, wie man es b it t h t i tbereits von cout gewohnt ist.

    – Die Stringklasse, für die der Ausgabeoperator

  • 1.4.7 Explizite Typumwandlung1.4.7 Explizite Typumwandlung

    ● static_cast-Operator– Syntax: static_cast(Ausdruck)– Implizit erlaubte Typumwandlungen (z.B. int double oder int

    enum) werden explizit vorgegeben.– static_cast lässt nur bestimmte (sinnvolle) Umwandlungen zu.

    ● dynamic_cast-OperatorZeiger und Referenzen auf Klassen mit virtuellen Methoden müssen per– Zeiger und Referenzen auf Klassen mit virtuellen Methoden müssen per dynamic_cast gewandelt werden.Dazu am Ende des Semesters mehr …

    ● reinterpret cast Operator● reinterpret_cast-Operator– Castet alles und ist damit sehr gefährlich! Nur in begründeten

    Ausnahmefällen verwenden.

    Prof. Dr. Andreas Simon

    – Der „Java-Style-Cast“ (neuerTyp)var ist noch möglich und entspricht dem reinterpret_cast-Operator.

    56C++-GrundlagenDatentypen Explizite Typumwandlung

  • 1.5 Funktionen, Grundlagen1.5 Funktionen, Grundlagen● Deklaration

    – Syntax (Bezeichner var1, varN sind optional):

  • 1.5 Funktionen, Grundlagen1.5 Funktionen, Grundlagen● Implementation / Definition

    – Syntax:Rü k b t F kti (T 1 1 T N N)Rückgabetyp Funktionsname(Typ1 var1, …, TypN varN){

    }}

    – Beispiel:

    // Implementation (beinhaltet Deklaration): // Implementation (beinhaltet Deklaration): p ( )double quadriere(double arg) { 

    return arg*arg; }

    p ( )double quadriere(double arg) { 

    return arg*arg; }

    – Eine Funktion darf nur einmal implementiert werden.– Die Implementation beinhaltet auch die Deklaration.

    Prof. Dr. Andreas Simon 58Funktionen

  • 1.5 Funktionen, Grundlagen1.5 Funktionen, Grundlagen● Header-Dateien

    – Deklarationen, die anderen Programmteilen bekannt gemacht werden ll d i H d D t i f tsollen, werden in Header-Dateien zusammengefasst.

    – Beispiel:

    // Header‐Datei: def hpp// Header‐Datei: def hpp// Header Datei: def.hpp double quadriere(double arg); // Header Datei: def.hpp double quadriere(double arg); 

    // C D t i d// C D t i d// Cpp‐Datei: quad.cpp #include "def.hpp"int wert = quadriere(2.5);

    // Cpp‐Datei: quad.cpp #include "def.hpp"int wert = quadriere(2.5);

    Prof. Dr. Andreas Simon 59Funktionen

  • 1.5 Funktionen, Grundlagen1.5 Funktionen, Grundlagen● Aufruf

    – Syntax:F kti ( 1 N)Funktionsname(var1, …, varN);ret = Funktionsname(var1, …, varN);

    – Beispiel:

    // Aufruf double wert = quadriere(2.5); quadriere(5.5); // sinnlos, da Ergebnis nicht übernommen wird. 

    t d i ( d i (2 0)) // V k tt

    // Aufruf double wert = quadriere(2.5); quadriere(5.5); // sinnlos, da Ergebnis nicht übernommen wird. 

    t d i ( d i (2 0)) // V k tt

    – Funktionen können andere Funktionen und sogar sich selbst aufrufen (Rekursion)

    wert = quadriere(quadriere(2.0)); // Verkettung wert = quadriere(quadriere(2.0)); // Verkettung 

    (Rekursion).

    Prof. Dr. Andreas Simon 60Funktionen

  • 1.6 Modulare Programmgestaltung1.6 Modulare Programmgestaltung● 1.6.1 Globale Funktionen

    – Eine wichtige Errungenschaft der Objektorientierung besteht darin, dass M th d d V i bl f t i i Kl d t i d dMethoden und Variablen fast immer einer Klasse zugeordnet sind und nicht irgendwo „wild herumliegen“. Kapselung von inhaltlich zusammengehörenden Programmteilen.

    f ( )– In Ausnahmefällen (und davon gibt es nur sehr wenige) können Methoden auch ohne Klassenzugehörigkeit implementiert werden. Diese Methoden heißen Funktionen.

    – Man kann auch sagen, dass Methoden spezielle Funktionen sind, die zu einer Klasse gehören (auch Member-Funktionen).

    – Wenn auf diese Funktionen von überall aus zugegriffen werden kann, spricht man auch von globalen Funktionen.

    Prof. Dr. Andreas Simon 61C++-GrundlagenModulare Programmgestaltung

  • 1.6 Modulare Programmgestaltung1.6 Modulare Programmgestaltung● 1.6.2 Globale Variablen

    – Analog zu den Funktionen, gibt es auch Variablen, die zu keiner Klasse hö Di V i bl b i h t h l l b l V i blgehören. Diese Variablen bezeichnet man auch als globale Variablen.

    – Globale Variablen zeugen i. Allg. von einem schlechten Softwaredesign und sollten nach Möglichkeit vermieden werden.

    – Faustregel: Nur ein globales Datenobjekt pro Anwendung!

    int globaleVariable;class Klasse {int globaleVariable;class Klasse {class Klasse {

    int memberVariable;void methode() {

    // ...

    class Klasse {int memberVariable;void methode() {

    // ...}

    };void globaleFunktion() {

    //

    }};void globaleFunktion() {

    //

    Prof. Dr. Andreas Simon 62C++-GrundlagenModulare Programmgestaltung

    // ...}

    // ...}

  • 1.6 Modulare Programmgestaltung1.6 Modulare Programmgestaltung● 1.6.3 Funktionsprototyp

    – Der C++-Compiler kann nur Variablen und Funktionen ansprechen, die ih b k t ht dihm zuvor bekannt gemacht wurden.

    – Beispiel:

    void funktion1 () // Funktionsdefinitionvoid funktion1 () // Funktionsdefinitionvoid funktion1 () // Funktionsdefinition{

    funktion2 (); // error: "funktion2 " wurde nicht gefunden.}

    void funktion1 () // Funktionsdefinition{

    funktion2 (); // error: "funktion2 " wurde nicht gefunden.}}

    void funktion2 () // Funktionsdefinition{

    funktion1(); // i O

    }

    void funktion2 () // Funktionsdefinition{

    funktion1(); // i Ofunktion1(); // i.O.}

    funktion1(); // i.O.}

    Prof. Dr. Andreas Simon

    – Wie können sich zwei Funktionen gegenseitig aufrufen?

    63C++-GrundlagenModulare Programmgestaltung

  • 1.6 Modulare Programmgestaltung1.6 Modulare Programmgestaltung● 1.6.3 Funktionsprototyp

    – Der Funktionsprototyp sichert dem Compiler zu, dass die Funktion i d d d fi i t dirgendwo anders definiert wurde.

    – Beispiel:

    id f kti 2 () // F kti t t (F kti d kl ti )id f kti 2 () // F kti t t (F kti d kl ti )void funktion2 (); // Funktionsprototyp (Funktionsdeklaration)

    void funktion1 () // Funktionsdefinition{

    void funktion2 (); // Funktionsprototyp (Funktionsdeklaration)

    void funktion1 () // Funktionsdefinition{{

    funktion2 (); // jetzt i.O.}

    void funktion2 () // Funktionsdefinition

    {funktion2 (); // jetzt i.O.

    }

    void funktion2 () // Funktionsdefinitionvoid funktion2 () // Funktionsdefinition{

    funktion1(); // i.O.}

    void funktion2 () // Funktionsdefinition{

    funktion1(); // i.O.}

    Prof. Dr. Andreas Simon 64C++-GrundlagenModulare Programmgestaltung

    }}

  • 1.6 Modulare Programmgestaltung1.6 Modulare Programmgestaltung● 1.6.3 Funktionsprototyp

    – Die Funktionsdefinition beinhaltet auch die Funktionsdeklaration.– Ob eine Funktion zu einem Funktionsprototypen tatsächlich existiert, wird

    vom Compiler nicht geprüft! – Beispiel:

    void funktion2 (); // Funktionsprototyp (Funktionsdeklaration)

    void funktion1 () // Funktionsdefinition

    void funktion2 (); // Funktionsprototyp (Funktionsdeklaration)

    void funktion1 () // Funktionsdefinition() //{

    funktion2 (); // auch i.O. Wo ist methode2???}

    () //{

    funktion2 (); // auch i.O. Wo ist methode2???}

    – Frage: Wer merkt eigentlich, dass methode2 fehlt?Antwort: Der Linker. (Später mehr…)

    Prof. Dr. Andreas Simon

    ( )

    65C++-GrundlagenModulare Programmgestaltung

  • 1.6 Modulare Programmgestaltung1.6 Modulare Programmgestaltung● 1.6.3 Funktionsprototyp mit Parametern

    – Der Funktionsprototyp muss die vollständige Signatur (Funktionsname, Rü k b t A t ) d F kti d t llRückgabetyp, Argumente) der Funktion darstellen.

    – Beispiel:

    id f kti 2(i t d bl b) // F kti t tid f kti 2(i t d bl b) // F kti t tvoid funktion2(int a, double b); // Funktionsprototyp

    void funktion1(){

    void funktion2(int a, double b); // Funktionsprototyp

    void funktion1(){{

    funktion2(1, 2.3); // Aufruf von funktion2}

    void funktion2(int a double b)

    {funktion2(1, 2.3); // Aufruf von funktion2

    }

    void funktion2(int a double b)void funktion2(int a, double b){

    funktion1(); }

    void funktion2(int a, double b){

    funktion1(); }

    Prof. Dr. Andreas Simon 66C++-GrundlagenModulare Programmgestaltung

    }}

  • 1.6 Modulare Programmgestaltung1.6 Modulare Programmgestaltung● 1.6.3 Funktionsprototyp (Besonderheiten)

    – Beim Funktionsprototyp können die Bezeichner der Argumente l d ( b i ht übli h)weggelassen werden (aber nicht üblich).

    – Anders als Funktionsdefinitionen können Funktionsprototypen mehrfach vom Compilerdurchlaufen werden.

    – Beispiel:

    void funktion2(int, double);     // ohne Bezeichnervoid funktion2(int a double b); // Wiederholung des Prototypenvoid funktion2(int, double);     // ohne Bezeichnervoid funktion2(int a double b); // Wiederholung des Prototypenvoid funktion2(int a, double b); // Wiederholung des Prototypenvoid funktion2(int a, double b); // Wiederholung des Prototypen

    void funktion1()

    void funktion2(int a, double b); // Wiederholung des Prototypenvoid funktion2(int a, double b); // Wiederholung des Prototypen

    void funktion1(){

    funktion2(1, 2.3); // Aufruf von funktion2}

    {funktion2(1, 2.3); // Aufruf von funktion2

    }

    Prof. Dr. Andreas Simon 67C++-GrundlagenModulare Programmgestaltung

  • 1.6 Modulare Programmgestaltung1.6 Modulare Programmgestaltung● 1.6.4 Arbeiten mit mehreren Quellcode-Dateien 1/2

    – Ziel: Aufteilung des Quellcodes (Programmtextes) auf mehrere Dateien.– Inhaltlich zusammenhängende Code-Fragmente werden in einer Datei

    zusammengefasst.– Vorteile:○ Code-Wiederverwendung in anderen Programmen○ Parallele Entwicklung im Team○ Versionskontrolle○ Versionskontrolle○ Übersichtlichkeit

    Prof. Dr. Andreas Simon 68C++-GrundlagenModulare Programmgestaltung

  • 1.6 Modulare Programmgestaltung1.6 Modulare Programmgestaltung● 1.6.4 Arbeiten mit mehreren Quellcode-Dateien 2/2

    – Ähnlich wie unter Java, werden Programme unter C++ auf mehrere D t i f t ilt ( ü b i ht)Dateien aufgeteilt (müssen es aber nicht).

    – Anders als bei Java, müssen sich die Dateinamen nicht auf einen Klassennamen beziehen.

    – Programmdateien von C++-Programmen enden typischerweise mit .cpp.– Funktionen können sich untereinander aufrufen, auch wenn sie in

    verschiedenen Dateien liegen. Über die Funktionsprototypen wird dem g p ypCompiler angezeigt, dass dies auch so ist.

    Prof. Dr. Andreas Simon 69C++-GrundlagenModulare Programmgestaltung

  • 1.6 Modulare Programmgestaltung1.6 Modulare Programmgestaltung● 1.6.4 Arbeiten mit mehreren Quellcode-Dateien

    Datei a.cpp: main.cpp:

    int a(int arg) { 

    return arg*arg; }

    int a(int arg) { 

    return arg*arg; }

    int a(int arg); // Prototyp int b(int arg); // Prototyp int c(int arg); // Prototyp 

    int a(int arg); // Prototyp int b(int arg); // Prototyp int c(int arg); // Prototyp 

    }}

    int a(int arg); int b(int arg)int a(int arg); int b(int arg)

    void main() { 

    std::cout

  • 1.6 Modulare Programmgestaltung1.6 Modulare Programmgestaltung● 1.6.4 Compiler und Linker

    – Der Compiler übersetzt jede *.cpp-Datei einzeln und erzeugt (fast) füh b C d (Obj kt C d ) ( i * bj d * D t i fü j dausführbaren Code (Objekt-Code) (eine *.obj oder *.o-Datei für jede

    *.cpp-Datei).– Zugriffe auf Funktionen oder Variablen aus einer anderen *.cpp-Datei

    C ( )werden vom Compiler noch mit Platzhaltern (symbolischen Namen) im Objektcode offen gehalten.

    – Erst der Linker verbindet (to link) die vom Compiler erzeugten Objektdateien zu einer ausführbaren *.exe-Datei (assembly). Die symbolischen Funktionsnamen in den Objektdateien werden dabei aufgelöst (to resolve).

    – Es gibt zwei verschiedene Arten von Linkerfehlern:1. Im Softwareprojekt fehlt etwas.

    (Oft wurde hierbei vergessen, eine cpp‐Datei einzubinden.)

    Prof. Dr. Andreas Simon

    2. Im Softwareprojekt ist etwas doppelt vorhanden.(Eine cpp‐Datei wurde beispielsweise zweimal eingebunden.)

    71C++-GrundlagenModulare ProgrammgestaltungCompiler und Linker

  • 1.6 Modulare Programmgestaltung1.6 Modulare Programmgestaltung● 1.6.4 Compiler und Linker (Build-Prozess)

    Quellcodea.cpp b.cpp c.cpp

    Objektcodeaus anderen Projekten

    bj b bj bj d bj lib*.lib-Datei besteht ausmehreren zusammen

    Compiler

    Objektcodea.obj b.obj c.obj d.obj e.lib

    Linker

    mehreren zusammen-gefassten *obj-Dateien

    Linker

    Prof. Dr. Andreas Simon 72C++-GrundlagenModulare ProgrammgestaltungCompiler und Linker

    Executable, Assemblyprog.exe

  • 1.6 Modulare Programmgestaltung1.6 Modulare Programmgestaltung● 1.6.4 Include-Konzept

    – Ausgangsproblem: Man möchte auf Elemente (z.B. Funktionen) if di i i d D t i d fi i t d ifzugreifen, die in einer anderen Datei definiert wurden, zugreifen.

    – Beispiel: Funktion a() aus Datei a.cpp wird von Funktion b() aus Datei b.cpp und aus Funktion c() aus Datei c.cpp aufgerufen.

    – Dem Compiler muss beim Übersetzen der Dateien b.cpp und c.cpp das Vorhandensein der Funktion a() angezeigt werden (über die Funktionsdeklaration oder einen Funktionsprototypen).

    – Dies müsste in jeder Datei erfolgen, die auf die externen Elemente zugreifen will. (Codedopplung!)

    – Lösung: Zu jeder cpp‐Datei werden alle sinnvollen Deklarationen (z.B. g j pp (Funktionsprototypen) in einer separaten Datei (Header-Datei) zusammengefasst.

    – Diese Datei kann dann bei Bedarf durch die Compiler-Anweisung

    Prof. Dr. Andreas Simon

    Diese Datei kann dann bei Bedarf durch die Compiler Anweisung #inlcude (vor dem eigentlichen Compilerlauf) eingebunden werden.

    73C++-GrundlagenModulare ProgrammgestaltungInclude-Konzept

  • 1.6 Modulare Programmgestaltung1.6 Modulare Programmgestaltung● 1.6.4 Lösung des Beispiels mit Header-Dateien

    a.hpp: c.hpp:a.cpp:

    int a (int arg);int a (int arg);

    int b (int arg);int b (int arg);

    b.hpp:

    int c (int arg);int c (int arg);int a (int arg) { 

    return arg*arg; }

    int a (int arg) { 

    return arg*arg; }

    #i l d " h "#i l d " h "

    main.cpp:

    int b (int arg);int b (int arg);}}

    #include "a.hpp"int b (int arg)#include "a.hpp"int b (int arg)

    b.cpp:

    #include "a.hpp"#include "b.hpp"#include "c.hpp" 

    oid main()

    #include "a.hpp"#include "b.hpp"#include "c.hpp" 

    oid main()

    int b (int arg) { 

    return a(arg)‐arg; }

    int b (int arg) { 

    return a(arg)‐arg; }c cpp: void main() 

    { std::cout

  • 1.6 Modulare Programmgestaltung1.6 Modulare Programmgestaltung● 1.6.4 Anmerkungen zu Header-Dateien

    – Grundsätzlich soll für jede *.cpp-Datei eine (gleichnamige) *.hpp-Datei (H d D t i) l t d di ll D kl ti thält di(Header-Datei) angelegt werden, die alle Deklarationen enthält, die öffentlich gemacht werden sollen.

    – In Header-Dateien gehören keine Implementationen (Ausnahme: inline-)Funktionen und Templates).

    – An die Stelle der #include-Direktiven treten die einzubindenden Header-Dateien (reine Textersetzung!).

    – Wird eine Header-Datei geändert, so werden alle *.cpp-Dateien neu compiliert, die diese Header-Datei einbinden. Daher …○ … sollten nur notwendige Header eingebunden werden.g g○ … sollten Header andere Header möglichst kaum einbinden

    (Reduktion von internen Abhängigkeiten (engl. dependencies).– Die Dateiendung bei Headerdateien kann (sollte aber nicht) beliebig sein

    Prof. Dr. Andreas Simon

    – Die Dateiendung bei Headerdateien kann (sollte aber nicht) beliebig sein.

    75C++-GrundlagenModulare ProgrammgestaltungInclude-Konzept

  • 1.6 Modulare Programmgestaltung1.6 Modulare Programmgestaltung● 1.6.5 Präprozessor-Direktiven …

    – steuern den Compiliervorgang;– werden zur Compilierzeit ausgeführt;– verhalten sich teilweise compiler-abhängig;– werden mit # eingeleitet;g ;– sollten sparsam verwendet werden.– #include ist beispielsweise eine Präprozessor-Direktive, die eine

    andere Datei an der Stelle der #include Direktive einfügtandere Datei an der Stelle der #include-Direktive einfügt.

    Prof. Dr. Andreas Simon 76C++-GrundlagenModulare ProgrammgestaltungCompiler-Direktiven

  • 1.6 Modulare Programmgestaltung1.6 Modulare Programmgestaltung● 1.6.6 Globale Variablen / Datenobjekte

    – Variablen, die außerhalb jeglicher Funktion deklariert werden, heißen l b l V i blglobale Variablen.

    – Globale Variablen sind von jeder Programmstelle aus erreichbar. Nachteil, da der Datenfluss im Programm intransparent wird!

    – Grundsatz: So wenige globale Variablen, wie möglich deklarieren. – Die Initialisierung erfolgt vor dem main()-Aufruf.– Das Vorhandensein globaler Variablen (in anderen Dateien) wird demDas Vorhandensein globaler Variablen (in anderen Dateien) wird dem

    Compiler durch extern angezeigt.

    Prof. Dr. Andreas Simon 77Modulare ProgrammgestaltungGlobale Variablen / Datenobjekte

  • 1.6 Modulare Programmgestaltung1.6 Modulare Programmgestaltung● 1.6.6 Globale Variablen

    – Analog zum Funktionsprototypen gibt es für globale Variablen eine t h d D kl ti ( t D kl ti )entsprechende Deklaration (extern-Deklaration).

    – Beispiel:

    int globaleVariable=0;int globaleVariable=0;a.cpp:

    i

    extern int globaleVariable;extern int globaleVariable;a.hpp:

    int globaleVariable 0;int globaleVariable 0;a.cpp:

    #include "a.hpp"

    void main() {

    #include "a.hpp"

    void main() {

    main.cpp:

    globaleVariable =3; std::cout

  • 1.6 Modulare Programmgestaltung1.6 Modulare Programmgestaltung● 1.6.6 Modulsichtbarkeit (module scope)

    – Bisher waren die Funktionen global, d.h. programmweit zugreifbar( f d P t t b d )(, sofern der Prototyp angegeben wurde).

    – Bei C++-Programmen sind die Funktionen meistens global oder die Methoden einer Klasse.

    – Die Sichtbarkeit von Funktionen und Variablen kann jedoch auch nur auf ihre cpp-Datei beschränkt werden. Dies erfolgt durch Deklaration mit dem Schlüsselwort static.

    – Achtung: static hat in diesem Zusammenhang nichts mit statischen Methoden in Sinne der Objektorientierung zu tun! Beispiel:

    static int dateilokaleVariable;static int dateilokaleVariable;static int dateilokaleVariable;

    static void dateilokaleFunktion(){

    static int dateilokaleVariable;

    static void dateilokaleFunktion(){

    Prof. Dr. Andreas Simon 79Modulare ProgrammgestaltungModulsichtbarkeit

    }}

  • 1.6 Modulare Programmgestaltung1.6 Modulare Programmgestaltung● 1.6.7 Namensräume (namespaces)

    – Bei der Verwendung von Programmbibliotheken oder der Einbindung von f d Q ll d k i d B i h h f hfremdem Quellcode kann es passieren, dass Bezeichner mehrfach verwendet werden.

    – Zur Lösung derartiger Namenskonflikte werden Programmteile in S ( )namentragende Sichtbarkeitsbereiche (namespaces) gruppiert.

    – Elemente eines Namespaces (z.B. globale Variablen, Funkionen oder Klassen) können von außerhalb des Namesspaces nur unter Angabe des Namespace-Namens angesprochen werden.

    – Namespaces sind ähnlich zu Paketen in Java.

    Prof. Dr. Andreas Simon 80C++-GrundlagenModulare Programmgestaltungnamespaces

  • 1.6.7 Namensräume1.6.7 Namensräume● Beispiel für einen Namenskonflikt

    // abc.h// abc.hQuellcode von Firma ABCint func();int func();

    // h// h

    Quellcode von Firma ABC

    // xyz.hint func();// xyz.hint func(); Quellcode von Firma XYZ

    #include "abc.h"#include "xyz.h"#include "abc.h"#include "xyz.h"

    int main() { 

    func(); // ??? }

    int main() { 

    func(); // ??? }

    Welche Funktion soll aufgerufen werden?

    Prof. Dr. Andreas Simon 81C++-GrundlagenModulare Programmgestaltungnamespaces

    }}

  • 1.6.7 Namensräume1.6.7 Namensräume● Beispiel zur Lösung eines Namenskonflikts

    // abc.h// abc.h #include "abc.h"#include "abc.h"

    namespace abc{ 

    int func();

    namespace abc{ 

    int func();

    #include "xyz.h"

    int main() {

    #include "xyz.h"

    int main() {int func(); 

    }int func(); 

    }{ 

    abc::func(); xyz::func(); 

    }

    { abc::func(); xyz::func(); 

    }// xyz.h

    namespace xyz{

    // xyz.h

    namespace xyz{

    #include "abc.h"using namespace abc; #include "abc.h"using namespace abc; 

    { int func(); 

    }

    { int func(); 

    }

    int main() { 

    func(); // abc::func}

    int main() { 

    func(); // abc::func}

    Prof. Dr. Andreas Simon 82C++-GrundlagenModulare Programmgestaltungnamespaces

    }}:: Sichtbarkeitsoperator(scope operator)

  • 1.6.7 Namensräume1.6.7 Namensräume● Eigenschaften von Namensräumen

    – Gleiche Namensräume können mehrfach definiert (=erweitert) werden.– Namensräume können geschachtelt werden.– Namensräume werden mittels using namespace in den aktuellen

    Sichtbarkeitsbereich (scope) importiert.– using namespace ist vergleichbar mit import in Java.– Werden Namensräume nicht importiert, müssen die Elemente des

    Namensraums über den vollqualifizierenden ElementnamenNamensraums über den vollqualifizierenden Elementnamen angesprochen werden.

    Prof. Dr. Andreas Simon 83C++-GrundlagenModulare Programmgestaltungnamespaces

  • 1.8 Referenzen* * LV l R f1.8 Referenzen● Eigenschaften

    – Deklaration: Typ& aliasName = variable;

    * genauer: LValue-Referenzen

    – Eine Referenz ist ein Verweis auf eine Variable.– Referenzen müssen bei der Deklaration initialisiert.– Referenzen verweisen immer auf die gleiche.Referenzen verweisen immer auf die gleiche.– Referenzen sind Zeigern (s.u.) immer vorzuziehen, wenn möglich!– Hauptanwendung: Parameterübergabe/-rückgabe an/von Funktionen.

    Prof. Dr. Andreas Simon 84C++-GrundlagenReferenzen

  • 1.8 Referenzen1.8 Referenzen● Beispiel

    int a =1; // Deklaration von Variable a int a =1; // Deklaration von Variable a int b =2; // Deklaration von Variable b int& ar1 =a; // Deklaration von Referenz ar1 (verweist auf a) int &ar2 =ar1; // Deklaration von Referenz ar2 (verweist auf a) int& ar4; // Fehler: Referenz wird nicht initialisiert!

    int b =2; // Deklaration von Variable b int& ar1 =a; // Deklaration von Referenz ar1 (verweist auf a) int &ar2 =ar1; // Deklaration von Referenz ar2 (verweist auf a) int& ar4; // Fehler: Referenz wird nicht initialisiert!int& ar4; // Fehler: Referenz wird nicht initialisiert! int &br1=b, &br2=b; // br1 und br2 verweisen ab jetzt auf b std::cout

  • 1.7 Zeiger1.7 Zeiger● Hintergrund

    – Zeiger (pointer) dienen – ähnlich wie Java-Referenzen – dazu, Variablen d Obj kt i di kt hund Objekte indirekt anzusprechen.

    ● Prinzip– Der Arbeitsspeicher des Rechners besteht aus Bytes.– Jedes Byte im Speicher hat eine Nummer (Adresse).– Eine Variable beansprucht eine Menge von hintereinander liegenden

    Bytes im Speicher.Bytes im Speicher.– Die Adresse des ersten Bytes ist die Adresse der Variablen / des

    Datenobjektes.Variablen die Adressen (von anderen Variablen) enthalten heißen– Variablen, die Adressen (von anderen Variablen) enthalten, heißen Zeiger (pointer).

    Prof. Dr. Andreas Simon 86C++-GrundlagenZeiger

  • 1.7 Zeiger1.7 Zeiger● Syntax

    – Deklaration von Zeigern: *;  *, *; *;  *, *;

    – Zuweisung einer Adresse (&: Adressoperator &): = &; // &: Adressoperator  = &; // &: Adressoperator 

    – Dereferenzierung eines Zeigers (*: Dereferenzierungsoperator):* = ; // wie = * = ; // wie = 

    – Null-Zeiger: = nullptr; // zeigt ins 'Nichts‚ nullptr == 0 = nullptr; // zeigt ins 'Nichts‚ nullptr == 0

    Prof. Dr. Andreas Simon 87C++-GrundlagenZeiger

       nullptr; // zeigt ins  Nichts‚  nullptr  0   nullptr; // zeigt ins  Nichts‚  nullptr  0

  • 1.7 Zeiger1.7 Zeiger● Beispiel: Zeiger p zeigt auf int-Variable i

    p &i i *p

    Adresse Inhalt0xabcd4500 0x20

    p   &i p

    int i = 32;0xabcd4501 0x000xabcd4502 0x000xabcd4503 0x000xabcd4504 0x00

    int* p = &i;0xabcd4505 0x450xabcd4506 0xcd0xabcd4507 0xab

    & &i

    Prof. Dr. Andreas Simon 88C++-GrundlagenZeiger

    &p p   &i

  • 1.7 Zeiger1.7 Zeiger● Beispiel

    int wert; // 4 Bytes im Speicher für ganze Zahl reservieren t 12 // S i h i h lt j t t 0C 00 00 00 (I t l F t)

    int wert; // 4 Bytes im Speicher für ganze Zahl reservieren t 12 // S i h i h lt j t t 0C 00 00 00 (I t l F t)wert = 12; // Speicherinhalt jetzt: 0C 00 00 00 (Intel‐Format) 

    // Zeiger auf eine int‐Variable deklarieren: int* zeigerAufInt; // zeigt zurzeit irgendwo hin!!! 

    wert = 12; // Speicherinhalt jetzt: 0C 00 00 00 (Intel‐Format) 

    // Zeiger auf eine int‐Variable deklarieren: int* zeigerAufInt; // zeigt zurzeit irgendwo hin!!! 

    // Zeiger auf Variable 'wert' richten: zeigerAufInt = &wert; // Zeiger zeigt jetzt auf wert 

    // V i bl ' t' Z i i li

    // Zeiger auf Variable 'wert' richten: zeigerAufInt = &wert; // Zeiger zeigt jetzt auf wert 

    // V i bl ' t' Z i i li// Variable 'wert' per Zeiger manipulieren: *zeigerAufInt = 13; // Speicherinhalt jetzt: 0D 00 00 00 // Variable 'wert' per Zeiger manipulieren: *zeigerAufInt = 13; // Speicherinhalt jetzt: 0D 00 00 00 

    Prof. Dr. Andreas Simon 89C++-GrundlagenZeiger

  • 1.7 Zeiger1.7 Zeiger● Gegenüberstellung Zeiger / Referenz

    Eigenschaft Referenz ZeigerEigenschaft Referenz Zeigerint v1,v2;

    Deklaration (allein) nicht möglich int *p1;Deklaration + Initialisierung int& r1 = v1; int *p2 = &v1;Umwandlung: Var.Ref./Ptr. automatisch &v1Umwandlung: Ref./Ptr.Var. automatisch *p1Derefenzierung v2 = r1; v2 = *p1;Neu Zuweisung nicht möglich p1 = p2;Neu-Zuweisung nicht möglich p1 = p2;Null-Referenz nicht möglich nullptr

    Prof. Dr. Andreas Simon 90C++-GrundlagenZeiger

  • 1.7 Zeiger1.7 Zeiger● Gegenüberstellung Zeiger / Referenz

    Eigenschaft Referenz ZeigerEigenschaft Referenz Zeigerint v1;

    int& r1 = v1; int *p1 = &v1;

    Aufruf von void m(int x) m(r1); m(*p1);Aufruf von void m(int* x) m(&r1); m(p1);

    m(nullptr);m(nullptr);

    Aufruf von void m(int& x) m(r1); m(*p1);

    Prof. Dr. Andreas Simon 91C++-GrundlagenZeiger

  • 1.7 Zeiger1.7 Zeiger● Verkettung von Zeigern („Zeiger auf Zeiger“)

    – Beispiel:

    char c  = 'a';  // c:  Variablechar *p  =  &c;  // p:  Zeiger auf c char **pp =  &p;  // pp: Zeiger auf Zeiger auf c 

    char c  = 'a';  // c:  Variablechar *p  =  &c;  // p:  Zeiger auf c char **pp =  &p;  // pp: Zeiger auf Zeiger auf c char n  = **pp; // Zeiger auf Zeiger auf c dereferenzieren. 

    n  = *p;  // wie oben char n  = **pp; // Zeiger auf Zeiger auf c dereferenzieren. 

    n  = *p;  // wie oben 

    char*&p &c

    a=b pp= p= c=

    a

    cpppchar** char

    *p*pppp pp *pp **pp

    p &p p *pb

    Prof. Dr. Andreas Simon 92C++-GrundlagenZeiger

    **pp c ‐‐‐‐ &c c

  • 1.7 Zeiger1.7 Zeiger● Zeiger …

    – enthalten Adressen auf Speicherbereiche;– ermöglichen direkten Zugriff auf Speicherinhalte;– enthalten Typinformation über Speicherinhalt;– setzen festen Ort von Variablen im Speicher voraus;setzen festen Ort von Variablen im Speicher voraus;– können "irgendwo" hin zeigen;– führen bei nachlässiger Programmierung häufig zu Programmabstürzen;

    ibt i ht i J– gibt es nicht in Java.

    Prof. Dr. Andreas Simon 93C++-GrundlagenZeiger

  • 1.9 Funktionen, Parameterübergabe1.9 Funktionen, Parameterübergabe● Parameterübergabe

    – In C++ gibt es drei Varianten, Parameter an eine Funktion zu übergeben: W t R f d Z iper Wert, per Referenz oder per Zeiger.

    – Alle drei Varianten sind für Grunddatentypen und Objektdatentypen möglich. (Unterschied zu Java!)

    – Bei der Wahl der Variante sind folgende Aspekte zu berücksichtigen:○ Welche Datenmenge soll übergeben werden?

    Große Datenmenge: Zeiger oder Referenzg g○ Müssen die Originaldaten des Aufrufers durch die Funktion geändert

    werden?Änderung Originaldaten: Zeiger oder Referenzg g g

    ○ Referenzen sind Zeigern – wenn möglich – immer vorzuziehen!

    Prof. Dr. Andreas Simon 94Funktionen

  • 1.9 Funktionen, Parameterübergabe1.9 Funktionen, Parameterübergabe● Parameterübergabe/-rückgabe per Wert

    – Beispiel:double quadriere (double arg) {  // entspricht: 

    // double arg=wert; (Deklaration von arg, Kopie von wert) return arg*arg; // wert=arg*arg; (Kopie zurück nach wert)

    double quadriere (double arg) {  // entspricht: 

    // double arg=wert; (Deklaration von arg, Kopie von wert) return arg*arg; // wert=arg*arg; (Kopie zurück nach wert)return arg arg; // wert=arg arg; (Kopie zurück nach wert) 

    }return arg arg; // wert=arg arg; (Kopie zurück nach wert) 

    }

    double wert=2.0; t d i ( t)

    double wert=2.0; t d i ( t)

    – Argumente werden kopiert (Rechenzeit!).

    wert = quadriere(wert); printf("2.0^2=%lf", wert);wert = quadriere(wert); printf("2.0^2=%lf", wert);

    – Funktion arbeitet mit Kopie der Argumente. (wie in Java)

    Prof. Dr. Andreas Simon 95Funktionen

  • 1.9 Funktionen, Parameterübergabe1.9 Funktionen, Parameterübergabe● Parameterübergabe per Zeiger

    – Beispiel:

    void quadriere (double* arg_p) { 

    if (arg_p != nullptr) // Nachteil: Zeiger kann ungültig sein! * (* ) * (* )

    void quadriere (double* arg_p) { 

    if (arg_p != nullptr) // Nachteil: Zeiger kann ungültig sein! * (* ) * (* )*arg_p = (*arg_p) * (*arg_p); 

    } *arg_p = (*arg_p) * (*arg_p); 

    double wert=2.0; d i (& t) // & hi Ad t

    double wert=2.0; d i (& t) // & hi Ad t

    – Zeiger kann ungültig sein. Abfrage erforderlich!

    quadriere(&wert); // &: hier Adressoperatorquadriere(&wert); // &: hier Adressoperator

    – Argumente werden nicht kopiert.– Funktion arbeitet mit den Original-Argumenten.

    Prof. Dr. Andreas Simon 96Funktionen

  • 1.9 Funktionen, Parameterübergabe1.9 Funktionen, Parameterübergabe● Parameterrückgabe per Zeiger

    – Der Rückgabezeiger muss auf Variable zeigen, die nach dem F kti d hl f h i ti t!Funktionsdurchlauf noch existiert!

    – Beispiel:

    double* quadriere (double* arg p)double* quadriere (double* arg p)double  quadriere (double  arg_p) { 

    if (arg_p != nullptr) *arg_p = *arg_p * *arg_p; 

    return arg p;

    double  quadriere (double  arg_p) { 

    if (arg_p != nullptr) *arg_p = *arg_p * *arg_p; 

    return arg p;return arg_p; }

    return arg_p; }

    double wert = 2.0; double wert = 2.0; *quadriere(&wert)=5.0; // möglich! Was passiert hier?*quadriere(&wert)=5.0; // möglich! Was passiert hier?

    Prof. Dr. Andreas Simon 97Funktionen

  • 1.9 Funktionen, Parameterübergabe1.9 Funktionen, Parameterübergabe● Parameterrückgabe per Zeiger

    – Negativ-Beispiele:

    double* quadriere (double arg) { 

    return arg*arg; // Compiler‐Fehler!

    double* quadriere (double arg) { 

    return arg*arg; // Compiler‐Fehler!// Zeiger muss zurückgegeben werden. 

    } // Zeiger muss zurückgegeben werden. 

    double* quadriere (double arg)double* quadriere (double arg)double  quadriere (double arg) { 

    double temp = arg*arg; return &temp; // Compiler‐Warnung! 

    // temp existiert gleich nicht mehr!

    double  quadriere (double arg) { 

    double temp = arg*arg; return &temp; // Compiler‐Warnung! 

    // temp existiert gleich nicht mehr!// temp existiert gleich nicht mehr! }

    // temp existiert gleich nicht mehr! }

    Prof. Dr. Andreas Simon 98Funktionen

  • 1.9 Funktionen, Parameterübergabe1.9 Funktionen, Parameterübergabe● Parameterübergabe per Referenz

    – Beispiel:

    void quadriere (double& arg) // &: hier Referenz {  // Referenzen müssen nicht explizit dereferenziert werden 

    arg = arg *arg; // Vorteil: Referenz ist immer gültig! 

    void quadriere (double& arg) // &: hier Referenz {  // Referenzen müssen nicht explizit dereferenziert werden 

    arg = arg *arg; // Vorteil: Referenz ist immer gültig! 

    – Argumente werden nicht kopiert.F kti b it t it d O i i l A t

    }}

    – Funktion arbeitet mit den Original-Argumenten.

    double wert=2.0; quadriere(wert); // Vorteil: Aufruf wie per Wert! double wert=2.0; quadriere(wert); // Vorteil: Aufruf wie per Wert! std::cout

  • 1.9 Funktionen, Parameterübergabe1.9 Funktionen, Parameterübergabe● Parameterübergabe per Referenz auf Konstante

    – Beispiel:

    double quadriere (double const& arg) {  // arg darf nicht verändert werden! 

    return arg*arg; // arg wird nicht verändert. 

    double quadriere (double const& arg) {  // arg darf nicht verändert werden! 

    return arg*arg; // arg wird nicht verändert. 

    – Argumente werden nicht kopiert.F kti b it t it d O i i l A t

    g g g} 

    g g g} 

    – Funktion arbeitet mit den Original-Argumenten.– Funktion kann Original-Argumente nicht ändern (nur lesend zugreifen).

    Prof. Dr. Andreas Simon 100C++-GrundlagenFunktionen

  • 1.9 Funktionen, Parameterübergabe1.9 Funktionen, Parameterübergabe● Parameterrückgabe per Referenz

    – Beispiel:

    double& quadriere (double& arg) { 

    arg = arg*arg; 

    double& quadriere (double& arg) { 

    arg = arg*arg; g g g;return arg; // wie Rückgabe per Wert 

    g g g;return arg; // wie Rückgabe per Wert 

    double wert = 2.0; quadriere(wert)=5.0; // möglich! Was passiert hier? double wert = 2.0; quadriere(wert)=5.0; // möglich! Was passiert hier? 

    Prof. Dr. Andreas Simon 101C++-GrundlagenFunktionen

  • 1.9 Funktionen, Parameterübergabe1.9 Funktionen, Parameterübergabe● Parameterrückgabe per Referenz auf Konstante

    – Beispiel:

    double const& quadriere (double& arg) { 

    arg = arg*arg; 

    double const& quadriere (double& arg) { 

    arg = arg*arg; return arg; 

    } return arg; 

    d bl t1 2 0d bl t1 2 0double wert1 = 2.0; double wert2 = quadriere(wert1); quadriere(wert1)=5.0; // nicht (mehr) möglich! 

    double wert1 = 2.0; double wert2 = quadriere(wert1); quadriere(wert1)=5.0; // nicht (mehr) möglich! 

    Prof. Dr. Andreas Simon 102C++-GrundlagenFunktionen

  • 1.9 Funktionen, Parameterübergabe1.9 Funktionen, Parameterübergabe● Parameterrückgabe per Referenz

    – Negativ-Beispiele:

    double& quadriere (double& arg) { 

    return arg*arg; // Compiler‐Fehler!

    double& quadriere (double& arg) { 

    return arg*arg; // Compiler‐Fehler!return arg arg; // Compiler Fehler!// Welche Variable wird denn zurückgegeben? 

    return arg arg; // Compiler Fehler!// Welche Variable wird denn zurückgegeben? 

    double& quadriere (double& arg) { 

    double temp = arg*arg; return temp; // Compiler Warnung!

    double& quadriere (double& arg) { 

    double temp = arg*arg; return temp; // Compiler Warnung!return temp; // Compiler‐Warnung! 

    // temp existiert gleich nicht mehr! } 

    return temp; // Compiler‐Warnung! // temp existiert gleich nicht mehr! 

    Prof. Dr. Andreas Simon 103C++-GrundlagenFunktionen

  • 1.10 Arrays1.10 Arrays● Erzeugung

    – Erzeugung eines (statischen) Arrays:int array1DimC [100]; // ohne(!) Initialisierungint array1DimC [100]; // ohne(!) Initialisierung

    int array1DimC [100]={3,4,5,...,7,5,3}; // mit Initialisierungslisteint array1DimC [100]={3,4,5,...,7,5,3}; // mit Initialisierungsliste

    – Anders als in Java stehen die Klammern [] immer hinter dem

    int array1DimC [] = {3,4,5,...,7,5,3}; // Compiler ermittelt Größeint array1DimC [] = {3,4,5,...,7,5,3}; // Compiler ermittelt Größe

    Arraybezeichner.

    – Der Schreib- und Lesezugriff auf das Array erfolgt wie in Java.

    – Statische Arrays werden wie lokale/globale Variablen erzeugt.

    – Die Lebensdauer statischer Arrays entsprechend denen lokaler/globaler Variablen.

    Prof. Dr. Andreas Simon

    Variablen.

    104C++-GrundlagenZeiger und Arrays

  • 1.10 Arrays1.10 Arrays● Erzeugung

    – Achtung: Anders als bei JAVA müssen die Größenangaben statischer A k t t i !Arrays konstant sein!// Größenangabe als Literal:int array1[10];// Größenangabe als Literal:int array1[10];

    // Größenangabe als Konstante:int constexpr GROESSE = 10;int array2[GROESSE];

    // Größenangabe als Konstante:int constexpr GROESSE = 10;int array2[GROESSE];

    – Bei statischen Arrays muss deren Größe zur Compilierzeit bekannt sein.

    Prof. Dr. Andreas Simon 105C++-GrundlagenZeiger und Arrays

  • 1.10 Arrays1.10 Arrays● Erzeugung

    – Variable Größenangaben statischer Arrays werden vom C++-ISO-St d d i ht t tüt t ( hl b C il )!Standard nicht unterstützt (wohl aber vom Compiler g++)!int groesse = 10;int array3[groesse]; //

  • 1.10 Arrays1.10 Arrays● Zeigerarithmetik

    – Neu: Der Arrayname ist zugleich der Zeiger auf das erste Arrayelement. Z i Mö li hk it f d t A l t if Zwei Möglichkeiten, auf das erste Arrayelement zuzugreifen:array1DimC[0] = 123; // Zugriff über Indexoperator (wie in Java)*array1DimC   = 123; // Zugriff per Zeigerarray1DimC[0] = 123; // Zugriff über Indexoperator (wie in Java)*array1DimC   = 123; // Zugriff per Zeiger

    – Frage: Wie kann man per Zeiger auf das zweite Arrayelement zugreifen?– Lösung (trivial):

    i t* &( 1Di C[1]) //< Ad d 2 El t h li t* &( 1Di C[1]) //< Ad d 2 El t h l

    – Lösung (Zeigerarithmetik):

    int* p = &(array1DimC[1]); //

  • 1.10 Arrays1.10 Arrays● Zeigerarithmetik

    – Zeiger lassen sich gezielt verschieben:

    – Der Compiler errechnet anhand des Zeigertyps (Arraytyps), die neue physikalische Adresse zu einer Zeigeroperation.

    Prof. Dr. Andreas Simon 108C++-GrundlagenZeiger und Arrays

    Bildquelle: Knut Stolze, Lehrstuhl für Datenbanken und Informationssysteme, Fakultät für Mathematik und Informatik, Uni Jena

  • 1.10 Arrays1.10 Arrays● Zeigerarithmetik

    – Beispiel int werte [5] = {4,6,2,4,‐1}; // int‐Array über 5 Zahlen *werte = ‐12; // Ersten Wert ändern. // *werte identisch mit werte[0] 

    int werte [5] = {4,6,2,4,‐1}; // int‐Array über 5 Zahlen *werte = ‐12; // Ersten Wert ändern. // *werte identisch mit werte[0] 

    // Zeiger auf ersten Wert: int* wertZeiger = werte; // oder: wertZeiger=&werte[0] 

    // Zeiger auf zweiten Wert: 

    // Zeiger auf ersten Wert: int* wertZeiger = werte; // oder: wertZeiger=&werte[0] 

    // Zeiger auf zweiten Wert: // gwertZeiger=wertZeiger+1; // oder: wertZeiger=&werte[1]; 

    // Dritten Wert ändern: werte[2]=1; // oder *(werte+2)=1 

    // gwertZeiger=wertZeiger+1; // oder: wertZeiger=&werte[1]; 

    // Dritten Wert ändern: werte[2]=1; // oder *(werte+2)=1 [ ] ; // ( )[ ] ; // ( )

    Prof. Dr. Andreas Simon 109C++-GrundlagenZeiger und Arrays

  • 1.10 Arrays1.10 Arrays● Zeigerarithmetik

    – Ein Ausdruck der Form

    – … ist identisch mit dem Ausdruck (Anwendung der Zeigerarithmetik)

    arrayname[index]arrayname[index]

    … ist identisch mit dem Ausdruck (Anwendung der Zeigerarithmetik)

    i t id ti h it d A d k (V t h d S d )

    *(arrayname+index)*(arrayname+index)

    – … ist identisch mit dem Ausdruck (Vertauschung der Summanden)

    *(index+arrayname)*(index+arrayname)

    – … ist identisch mit dem Ausdruck (!)

    index[arrayname]index[arrayname]

    Prof. Dr. Andreas Simon 110C++-GrundlagenZeiger und Arrays

  • 1.10 Arrays1.10 Arrays● Übergabe eindimensionaler Arrays

    – Möglichkeiten zur Übergabe:

    void aendereElement_2(int *z   ) { z[1]++; }void aendereElement_2(int *z   ) { z[1]++; }

    void aendereElement_1(int z[] ) { z[1]++; }void aendereElement_1(int z[] ) { z[1]++; }

    F kti f f

    void aendereElement_3(int z[4]) { z[1]++; }void aendereElement_3(int z[4]) { z[1]++; } – Funktionsaufrufe:int zahlen [] = {‐1,4,7,10};

    aendereElement 1(zahlen);

    int zahlen [] = {‐1,4,7,10};

    aendereElement 1(zahlen);aendereElement_1(zahlen);aendereElement_2(zahlen);aendereElement_3(zahlen);

    aendereElement_1(zahlen);aendereElement_2(zahlen);aendereElement_3(zahlen);

    Prof. Dr. Andreas Simon 111C++-GrundlagenZeiger und Arrays

  • 1.10 Arrays1.10 Arrays● Größenabfrage von Arrays (mit sizeof)

    – Einfache C-Arrays sind anders als bei Java keine Objekte und tragen h k i I f ti üb ih G öß B i i lauch keine Information über ihre Größe. Beispiel:

    void nimmArray (double a[10]) {cout

  • 1.10 Arrays1.10 Arrays● Zweidimensionale Arrays

    – Zweidimensionale Arrays sind eindimensionale Arrays vom Typi di i l A ( i b i J )eindimensionaler Arrays (wie bei Java).

    – Erzeugung eines statischen Arrays der Größe 2 vom Typ int[3]:int array2DimC [2][3]; // ohne Initialisierung, 2 „Zeilen“, 3 „Spalten“int array2DimC [2][3]; // ohne Initialisierung, 2 „Zeilen“, 3 „Spalten“

    int array2DimC [][3] = {{1,2,3},{4,5,6}}; // Größe durch Compilerint array2DimC [][3] = {{1,2,3},{4,5,6}}; // Größe durch Compiler

    int array2DimC [2][3] = {{1,2,3},{4,5,6}}; // Initialisierungslisteint array2DimC [2][3] = {{1,2,3},{4,5,6}}; // Initialisierungsliste

    – Anordnung der Arrayelemente im Speicher:{1,2,3,4,5,6}{1,2,3,4,5,6}

    – Jede Zeile eines statischen Arrays enthält gleich viele Elemente Statische Arrays sind immer „matrixförmig“.

    Prof. Dr. Andreas Simon

    y g

    113C++-GrundlagenZeiger und Arrays

  • 1.10 Arrays1.10 Arrays● Zweidimensionale Arrays

    – Komponenten der Arraydeklaration zweidimensionaler Arrays

    int array2DimC [2][3]; // Arraytypint array2DimC [2][3]; // Arraytyp

    int array2DimC [2][3]; // Arrayname, Zeiger auf 1. Elementint array2DimC [2][3]; // Arrayname, Zeiger auf 1. Element

    ö li h

    int array2DimC [2][3]; // Arraygroesseint array2DimC [2][3]; // Arraygroesse

    – möglich:

    int array2DimC [][3] = {{1,2,3},{4,5,6}}; // Größe durch Compilerint array2DimC [][3] = {{1,2,3},{4,5,6}}; // Größe durch Compiler

    – nicht möglich, da Arraytyp unvollständig ist:

    int array2DimC [][] = {{1,2,3},{4,5,6}}; // FEHLER!!!int array2DimC [][] = {{1,2,3},{4,5,6}}; // FEHLER!!!

    Prof. Dr. Andreas Simon 114C++-GrundlagenZeiger und Arrays

  • 1.10 Arrays1.10 Arrays● Zweidimensionale Arrays

    – Beispiel: 2x3-Matrix

    654321

    matrix

    int matrix[2][3] = {{1,2,3}, {4,5,6}}; int matrix[2][3] = {{1,2,3}, {4,5,6}}; 

    654

    Ausdruck Typ Zeigerarithmetik Bedeutungmatrix int (*) [3] matrix+0 zeigt auf {1,2,3}&matrix[1] int (*) [3] matrix+1 zeigt auf {4 5 6}&matrix[1] int (*) [3] matrix+1 zeigt auf {4,5,6}matrix[0] int* *(matrix+0) zeigt auf 1matrix[1] int* *(matrix+1) zeigt auf 4

    Prof. Dr. Andreas Simon 115C++-GrundlagenZeiger und Arrays

    gmatrix[1][1] int *(*(matrix+1)+1) Element „5“

  • 1.10 Arrays1.10 Arrays● Übergabe zweidimensionaler Arrays

    – Möglichkeiten für statische Arrays:

    void aendereElement_2(int z[][2]) { z[1][1]++; } void aendereElement_2(int z[][2]) { z[1][1]++; } 

    void aendereElement_1(int z[3][2]) { z[1][1]++; }void aendereElement_1(int z[3][2]) { z[1][1]++; }

    void aendereElement_3(int (*z) [2]) { z[1][1]++; }void aendereElement_3(int (*z) [2]) { z[1][1]++; }

    void aendereElement_4(int *z     ) { z[1*2+1]++; }void aendereElement_4(int *z     ) { z[1*2+1]++; }

    – Funktionsaufrufe:int zahlen [][2] = {{1,2},{3,4},{4,5}};int zahlen [][2] = {{1,2},{3,4},{4,5}};[][ ] {{ } { } { }}

    aendereElement_1(zahlen);aendereElement_2(zahlen);aendereElement_3(zahlen);

    [][ ] {{ } { } { }}

    aendereElement_1(zahlen);aendereElement_2(zahlen);aendereElement_3(zahlen);

    Prof. Dr. Andreas Simon 116C++-GrundlagenZeiger und Arrays

    aendereElement_4(reinterpret_castzahlen);aendereElement_4(&(zahlen[0][0]));aendereElement_4(reinterpret_castzahlen);aendereElement_4(&(zahlen[0][0]));

  • 1.10 Arrays1.10 Arrays● Eigenschaften von Arrays allgemein

    – Die Größe eines Arrays muss separat gespeichert bzw. übergeben dwerden.

    – Arrays werden immer indirekt an Funktionen übergeben bzw. von denen zurückgegeben (Call-by-Reference).

    – Funktionen arbeiten immer direkt mit dem Originalarray und nicht mit dessen Kopie.

    ● Eigenschaften statischer Arraysg y– Die Arraygröße muss zur Compilerlaufzeit bekannt sein.

    Größenangabe nur durch Literal (Zahl) oder Konstante– Die Lebensdauer der Arrays ist fest vorgegeben und ist identisch mitDie Lebensdauer der Arrays ist fest vorgegeben und ist identisch mit

    derer von lokalen bzw. globalen Variablen.– Abhilfe schaffen hierbei dynamische Arrays (s.u.).

    Prof. Dr. Andreas Simon 117C++-GrundlagenZeiger und Arrays

  • 1.11 Dynamische Datenobjekte1.11 Dynamische Datenobjekte● Eigenschaften

    – Speicher wird dynamisch (d.h. zur Laufzeit) durch new angefordert und d h d l t i d f i bdurch delete wieder freigegeben.

    – Speicher wird nicht automatisch freigegeben! Es besteht die Gefahr von sog. Speicher-Lecks.

    – Speicheranforderung kann abgewiesen werden. Fehlerbehandlung erforderlich.

    – Speicheranforderung und -freigabe besitzt nicht-deterministisches p g gLaufzeitverhalten.

    Prof. Dr. Andreas Simon 118C++-GrundlagenDynamische Datenobjekte

  • 1.11 Dynamische Datenobjekte1.11 Dynamische Datenobjekte● Syntax

    – Einfache Variable:Typ* zeiger = new Typ; // anfordern*zeiger = ; // verwendendelete zeiger; // freigeben

    – Array (1-dimensional):Typ* zeiger = new Typ [anz]; // anforderndelete [] zeiger; // freigeben[] g ; g

    – Array (2-dimensional):Typ (*zeiger)[spalten] = new Typ [zeilen][spalten];delete [] zeiger;delete [] zeiger;

    violett: Datentyp

    Prof. Dr. Andreas Simon 119C++-GrundlagenDynamische Datenobjekte

  • 1.11 Dynamische Datenobjekte1.11 Dynamische Datenobjekte● Beispiele:

    // dynamisch erzeugte Variable: // dynamisch erzeugte Variable: int* zahl_p = new int; // violett: Datentyp *zahl_p = 5; delete zahl_p; // dynamisch erzeugtes eindimensionales Feld:

    int* zahl_p = new int; // violett: Datentyp *zahl_p = 5; delete zahl_p; // dynamisch erzeugtes eindimensionales Feld:// dynamisch erzeugtes eindimensionales Feld: double* feld1 = new double[4]; // violett : Datentyp feld1[2] = 1.4; delete [] feld1; 

    // dynamisch erzeugtes eindimensionales Feld: double* feld1 = new double[4]; // violett : Datentyp feld1[2] = 1.4; delete [] feld1; 

    Darf jetzt auch Variable sein!// dynamisch erzeugtes 2‐dimensionales Feld: char (*feld2)[4] = new char[5][4]; // violett : Datentyp delete [] feld2; // dynamisch erzeugtes 3‐dimensionales Feld:

    // dynamisch erzeugtes 2‐dimensionales Feld: char (*feld2)[4] = new char[5][4]; // violett : Datentyp delete [] feld2; // dynamisch erzeugtes 3‐dimensionales Feld:// dynamisch erzeugtes 3 dimensionales Feld: int (*feld3)[4][3] = new int[5][4][3]; // violett : Datentyp delete [] feld3;

    // dynamisch erzeugtes 3 dimensionales Feld: int (*feld3)[4][3] = new int[5][4][3]; // violett : Datentyp delete [] feld3;

    Prof. Dr. Andreas Simon 120C++-GrundlagenDynamische Datenobjekte

  • 1.11 Dynamische Datenobjekte1.11 Dynamische Datenobjekte● Eigenschaften von dynamischen Datenobjekten allgemein

    – Dyn. Datenobjekte können Variablen, Arrays oder Objekte von Klassen isein.

    – Dyn. Datenobjekte werden mit new erzeugt.– new liefert einen Zeiger auf das neue Objekt.– Dyn. Datenobjekte leben solange, bis sie mit delete gelöscht werden.– Die Lebensdauer dyn. Datenobjekte kann flexibel vorgegeben werden.

    ● Eigenschaften dynamischer Arrays● Eigenschaften dynamischer Arrays– Die Arraygröße (erster Index) braucht erst zur Laufzeit bekannt zu sein. Variable als Arraygröße zulässig.D A d i ht it d l t d it d l t [] lö ht!– Dyn. Arrays werden nicht mit delete sondern mit delete[] gelöscht!

    – Um alle Dimensionen eines dynamischen Arrays zur Programmlaufzeit per Variable vorgeben zu können, sind mehrere Schritte notwendig …

    Prof. Dr. Andreas Simon 121C++-GrundlagenDynamische Datenobjekte

  • 1.11 Dynamische Datenobjekte1.11 Dynamische Datenobjekte● Mehrdimensionale verteilte Arrays

    – Dynamische Arrays müssen nicht matrixförmig sein, d.h. die Größe der Z il k iiZeilen kann variieren.

    – Die Elemente dynamischer Arrays können verteilt sein, müssen also nicht kompakt (hintereinander) im Speicher liegen.

    – Mehrdimensionale verteilte dynamische Arrays werden durch mehrere (mindestens zwei) 1-dimensionale Arrays gebildet, die teilweise aufeinander verweisen.

    – Ein 2-dimensionales verteiltes dynamisches Array besteht aus einem Zeigerarray, welches auf die Zeilen des Arrays verweist und mindestens einem Datenarray, welches die Elemente beherbergt.

    Prof. Dr. Andreas Simon 122C++-GrundlagenDynamische Datenobjekte

  • 1.11 Dynamische Datenobjekte1.11 Dynamische Datenobjekte● Mehrdimensionale verteilte Arrays

    – Erzeugung eines kompakten, matrixförmigen, 2-dimensionalen d i h Adynamischen Arrays:

    // Zeilenarray erzeugen: int** array2DimP2x3 = new int*[2]; // 2 Zeilen // Zeilenarray erzeugen: int** array2DimP2x3 = new int*[2]; // 2 Zeilen 

    // Datenarray erzeugen: int* daten = new int[2*3]; // 2x3=6 Elemente // Datenarray erzeugen: int* daten = new int[2*3]; // 2x3=6 Elemente 

    // Zeilenarray initialisieren: for (int idx=0; idx

  • 1.11 Dynamische Datenobjekte1.11 Dynamische Datenobjekte● Mehrdimensionale verteilte Arrays

    – Freigabe eines kompakten 2-dimensionalen dynamischen Arrays:// 1. Datenarray freigeben: delete [] daten; 

    // 2. Zeilenarray freigeben:

    // 1. Datenarray freigeben: delete [] daten; 

    // 2. Zeilenarray freigeben:// 2. Zeilenarray freigeben: delete [] array2DimP2x3;// 2. Zeilenarray freigeben: delete [] array2DimP2x3;

    Prof. Dr. Andreas Simon 124C++-GrundlagenDynamische Datenobjekte

  • 1.11 Dynamische Datenobjekte1.11 Dynamische Datenobjekte● Mehrdimensionale verteilte Arrays

    – Erzeugung eines verteilten (nicht-kompakten) und nicht-matrixförmigen2 di i l d i h A2-dimensionalen dynamischen Arrays:

    // Zeilenarray erzeugen (Pointer‐Array): int** array2DimP2x = new int*[2]; // 2 Zeilen // Zeilenarray erzeugen (Pointer‐Array): int** array2DimP2x = new int*[2]; // 2 Zeilen 

    // Zeilenarray initialisieren: for (int idx=0; idx

  • 1.11 Dynamische Datenobjekte1.11 Dynamische Datenobjekte● Mehrdimensionale verteilte Arrays

    – Freigabe eines verteilten (nicht-kompakten) 2-dimensionalen d i h Adynamischen Arrays:

    for (int idx=0; idx

  • 1.11 Dynamische Datenobjekte1.11 Dynamische Datenobjekte● Hinweise

    – Datenobjekte die zuletzt erzeugt wurden, sollten zuerst gelöscht werden.– Für einfache Variablen und Arrays müssen verschiedene delete-

    Varianten verwendet werden (z.B. delete []).– Während des Programmlaufs new und delete sparsam verwenden

    (Fragmentierung des Speichers vermeiden).– Möglichst zu Programmbeginn Speicher einmalig reservieren und bei

    Programmende wieder freigeben.g g– Vor dem Löschen von Datenobjekten sicherstellen, dass diese nicht

    mehr verwendet werden.– new-Aufruf wirft bad alloc-Exception falls kein Speicher angefordertnew Aufruf wirft bad_alloc Exception, falls kein Speicher angefordert

    werden könnte.– Vor delete-Aufruf Zeiger auf Gültigkeit (nullptr) überprüfen.

    Nach delete Aufruf Zeiger auf nullptr setzen

    Prof. Dr. Andreas Simon

    – Nach delete-Aufruf Zeiger auf nullptr setzen.

    127C++-GrundlagenDynamische Datenobjekte

  • 1.11 Zeiger, Vertiefung1.11 Zeiger, Vertiefung● Unterschied: konstanter Zeiger, Zeiger auf Konstante

    – Zeiger auf Konstante:int const ZAHL = 1;        // Konstante deklarierenint const *zeiger_I = &ZAHL; // Zeiger auf Konstante*zeiger_I = 2; // Konstante ändern  : nicht möglichzeiger I++; // Zeiger verschieben: möglich

    int const ZAHL = 1;        // Konstante deklarierenint const *zeiger_I = &ZAHL; // Zeiger auf Konstante*zeiger_I = 2; // Konstante ändern  : nicht möglichzeiger I++; // Zeiger verschieben: möglich

    – konstanter Zeiger auf Variable:

    zeiger_I++;    // Zeiger verschieben: möglichzeiger_I++;    // Zeiger verschieben: möglich

    i t hl 1 // V i bl d kl ii t hl 1 // V i bl d kl iint zahl = 1;               // Variable deklarierenint * const ZEIGER_i = &zahl; // konstanter Zeiger auf Variable*ZEIGER_i = 2; // Variable ändern   : möglichZEIGER_i++;    // Zeiger verschieben: nicht möglich

    int zahl = 1;               // Variable deklarierenint * const ZEIGER_i = &zahl; // konstanter Zeiger auf Variable*ZEIGER_i = 2; // Variable ändern   : möglichZEIGER_i++;    // Zeiger verschieben: nicht möglich

    – konstanter Zeiger auf Konstante:int const * const ZEIGER_I = &ZAHL; int const * const ZEIGER_I = &ZAHL; 

    Prof. Dr. Andreas Simon 128C++-GrundlagenZeiger und Arrays

    *ZEIGER_I = 2; // Variable ändern   : nicht möglichZEIGER_I++;    // Zeiger verschieben: nicht möglich*ZEIGER_I = 2; // Variable ändern   : nicht möglichZEIGER_I++;    // Zeiger verschieben: nicht möglich

  • 1.11 Zeiger, Vertiefung1.11 Zeiger, Vertiefung● Unterschied: konstanter Zeiger, Zeiger auf Konstante

    – Beispiel

    int i=1;int a=2;

    int *pi &i; // pi: