Wie ist C++ entstanden ?
Was
leistet die Sprache ?
Für welche Art von Programmen ist sie
ausgelegt ?
Was bringt mir das für mein Projekt ?
Die
Nähe zu C
Der neue Datentyp "bool".
Referenzen sind
initialisierte Zeiger.
Referenzen in Aufrufparametern vermeiden
Zeiger.
Funktions-Überladung: mehrere Funktionen mit
gleichem Namen,
unterschieden wird durch die
Parameter.
Einfacheres Allokieren und Freigeben von
Heap-Speicher.
IO mit einer komfortablen Klassenbibliothek.
Überbegriffe bilden, Klassifizieren tun wir
ständig,
warum nicht auch beim
Programmieren.
Die Klasse ist der Bauplan.
Das
Programm arbeitet letztendlich mit Objekten.
Wie finde ich Klassen ? Durch Abstrahieren.
Warum ist Verkapselung so wichtig
?
Wie werde ich darin von C++ unterstützt ?
Code wieder
verwenden durch Vererbung.
Vererbung stellt eine "Ist"
- Beziehung dar.
Es gibt auch die "Hat" - Beziehung, die
Aggregation.
Eine Klasse kann von mehreren Klassen
erben.
Über eine Objekt-Liste iterieren und je nach
Objekt-Typ
reagieren - Der Polymorphismus, ein
Highlight von OOP.
Abstrakte Klassen liefern Code,
fordern aber auch eine
Implementierung.
Wie wird eine Klasse in C++ geschrieben ?
Variable
sollten immer privat sein.
Dafür schreibe wir dann public
Zugriffsfunktonen.
Klassen haben Methoden.
Hat jedes
Objekt seinen eigenen Code ?
Wie handelt C++ den Zugriff auf die Daten
? Über den "this - Zeiger".
Wenn alle Bankkonten den gleichen
Zinssatz haben,
wäre eine Objektvariable
Verschwendung - Die statische Variable
gehört
der Klasse, nicht dem Objekt
Für die "Konstruktion" eines Objektes gibt es den
Konstruktor.
Den Standard Konstruktor bekommen wir
vom Compiler zur Verfügung gestellt, aber
auch
nicht immer.
Oft ist es besser diesen doch selbst zu
schreiben.
Objekte sollten eigentlich nicht mit Standard
Konstruktoren initialisiert werden.
Objekte sollten auf
verschiedene Arten initialisiert werden können, daher schreiben
wir mehrere Konstruktoren
Konstruktoren heißen wie die
Klassen, die Überladung von Methoden ist
hier also
zwingend notwendig.
Schreiben wir Konstruktoren mit
Parametern, bekommen wir keinen Standard
Konstruktor mehr
zur Verfügung
gestellt, hier hilft nur selber schreiben, sofern wir
ihn
brauchen.
In C++ können Methoden
vorbelegte Parameter haben, das gilt auch für
Konstruktoren, sind alle Parameter vorbelegt, dann haben wir wieder einen
Standard-Konstuktor.
Objekte können über
andere Objekte initialisiert werden, wir erhalten
eine
Kopie. C++ kopiert Elementweise, auch Zeiger,
diese zeigen auf den gleichen
Heap Bereich. Das geht gut, bis die Objekte durch
einen vorhandenen Destruktor
gelöscht werden, ggf. wird der gleiche Bereich 2 mal freigegeben,
dann kracht es.
Die Lösung : Der
Kopier-Konstruktor.
Es gibt auch statische und globale
Objekte.
Was muss getan werden, wenn Objekte selbst Objekte
enthalten ?
Das äussere Objekt ruft das innere
Objekt über eine Initalisierungsliste auf.
Wie werden Objekte
entsorgt ? Über Destruktoren.
Wie ist die Aufrufreihenfolge
?
Es gibt 2 Möglichkeiten Arrays von Objekten anzulegen :
Ohne
gleichzeitige Initialisierung,
dann ist ein Default
Konstruktor erforderlich.
Mit
Initialisierung,
dann sind
beliebige Konstruktoren möglich.
Warum Exceptions
?
Mehrfache Catch Blöcke : zuerst spezifische
Exceptions dann allgemeine
Exceptions
abfangen.
Bitte Exceptions auch nur für Ausnahmen
verwenden, nicht für den
normalen Programmablauf
!
Mit "throw" Exceptions auslösen.
Vererbung dient zur Wiederverwendung von Code.
Abgeleite
Klassen stehen in einer "Ist"- Beziehung zur Basisklasse.
Es
gibt auch die "Hat" - Beziehung, die Aggregation.
Auf "Protected" - Member kann ungehindert von
abgeleiteten Klassen zugegriffen
werden, andere Klassen haben keinen
Zugriff. Der "protected" Zugriff wirkt für
abgeleitete Klassen wie
"public", ansonsten wie "private".
Hat die Basis-Klasse einen Default Konstruktor,
wird dieser automatisch von
der abgeleiteten Klasse aufgerufen.
Vorsicht:
Hat die Basis Klasse
einen Konstruktor mit Parametern, muss der Aufruf des
Basisklassen
Konstruktors im Konstruktor der abgeleiteten Klasse in einer
Initialisierungs-Liste erfolgen.
Wie ist der Aufruf und wie wird die
Liste übergeben ?
Wie ist die Aufrufreihenfolge der Konstruktoren
Destruktoren entsorgen
die Objekte
In C++ können Operatoren überladen werden. Sie werden wie eine Funktion
deklariert
und können dann in einem Ausdruck verwendet werden. Ohne
diese Möglichkeit wären
Ausdrücke wesentlich komplexer. Durch die Operator -
Überladung ergibt sich eine
intuitive
Schreibweise.
Welche Operatoren sollten überladen werden.
?
Ganz wichtig ist ein eigener Zuweisungsoperator, bei
Klassen, die Zeiger enthalten.
Hier treten die gleichen Probleme wie
bei der Objekt Erstellung auf.
Wie schaut die Implementierung aus
?
Welche Operatoren eignen sich
noch zum Überschreiben ?
Die Basisklasse enthält eine
Minimalimplementierung,
diese kann
auch nur aus { } bestehen.
Die abgeleiteten Klassen
haben die Möglichkeit eine eigene geeignetere
Implementierung anzugeben, ist sie vorhanden, wird sie
verwendet.
Wie
wird der Polymorphismus in C++ realisiert ?
Jede Klasse mit
virtuellen Funktionen erhält vom Compiler eine Tabelle zugeteilt.
Hier
werden die Adressen der virtuellen Funktionen eingetragen, es handelt sich
also
um
eine Sprung Tabelle, die VMT (Virtuelle Methoden
T abelle). Jedes Objekt dieser
Klasse erhält
in den ersten 4 Bytes seines Datenlayouts einen "hidden" Zeiger
auf die VMT.
Wie wird die richtige Methode gefunden ?
Wird die virtuelle Methode über ein Objekt aufgerufen,
weiß der Compiler welche
Funktion gemeint ist,
er bindet zur Compile-Time, das ist aber keine Polymorphismus.
Wird eine Methode über einen
Basisklassenzeiger aufgerufen, steht zur Compile-Time
nicht fest
welche Methode ausgeführt werden soll, je nach Typ im Zeiger wird ja ggf.
eine
andere Funktion ausgeführt, er muss Code erzeugen um die
Funktionsadresse zur
Laufzeit zu bestimmen.
Wie findet
die Anwendung zur Laufzeit die richtige Funktionsadresse ?
Im
referenzierten Objekt wird über den Zeiger _vfptr die Methoden Tabelle
geladen
und über einen Index
die entsprechende Funktionsadresse ermittelt , es wird also spät
gebunden.
Auch in OOP gibt es Freunde.
Diese Freundschaften werden von einer Klasse an
Funktionen oder an andere
Klassen
vergeben.
Die Freunde dürfen dann auf die privaten Member der
Klasse zugreifen.
Freundschaften werden jedoch
nicht vererbt.
C++ ist eine der wenigen Objektorientierten
Sprachen, die es erlauben von mehreren
Basisklassen Code zu
erben.
Wie wird diese Mehrfachvererbung realisiert
?
Wie ist der Objektaufbau
?
Vorteil
der "Multiple Inheritance" : intuitiver Zugriff.
Nachteil: Ambiguity
(Mehrdeutigkeit) bei gleichnamigen Methoden aus verschiedenen
Basis Klassen.
Wann brauche ich die virtuelle Vererbung
?
Es gibt 2 Arten von Templates
Klassen-Templates und Funktions-Templates
Warum Templates ?
Beispiel
Funktion Max: Sie gibt die größere Zahl von 2 Zahlen zurück. Für jeden
Max -Typ (short, int oder long) muss
eine neue Max-Funktion erstellt werden.
Es wären 3 Max-Funktionen zu
schreiben.
Die Lösung mit Templates:
Es wird eine allgemeine Funktion
geschrieben, die nicht den Typ short, int oder long
enthält sondern
einen allgemeinen Typ z.B. "T". Beim Aufruf der Funktion generiert
der Compiler zunächst den "richtigen Code" mit dem Typ, der beim
Aufruf verwendet wurde.
Bei 3 Aufrufen mit unterschiedlichen Typen
wird natürlich auch 3 mal unterschiedlicher
Code erzeugt, wir mussten
ihn aber nur einmal schreiben.
Wird die Max-Funktion mit dem gleichen Typ noch einmal
aufgerufen, dann wird der
schon vorhandene Code
verwendet.
Beide Argumente müssen den gleichen Datentyp haben.
Es erfolgt keinerlei
Typanpassung. Dafür gibt es mehrere Lösungen:
casten, Template Argument
explizit angeben, Wrapper erstellen
Das Template liefert in seiner ursprünglichen
Version nicht immer das erwartete
Ergebnis
zB.
Wird das Template Max für 2 Strings verwendet, so wird der Zeiger mit der
höheren Adresse zurückgegeben.
Lösung durch
Spezialisierungen von Template Funktionen.