Programmierkurs C++ Konstruktor, Statische Methoden Namespaces Prof. Dr. Stefan Fischer Institut für Telematik, Universität zu Lübeck http://www.itm.uni-luebeck.de/people/fischer
Initialisierung von Datenstrukturen Weiteres Problem prozeduraler Programmierung Initialisierung von Datenstrukturen Unklare Zuständigkeit Häufig nur durch Dokumentation ersichtlich Beispiel: Beim Verwenden der Datenstruktur Lampe muss zu Beginn die Funktion inithelligkeit(lampe* lampe); aufgerufen werden Wird häufig vergessen Führt potenziell zu undefiniertem bzw. ungewolltem Verhalten #2
#3 Wichtiges Prinzip: Konstruktion Instanzen können bei der Erzeugung automatisch initialisiert werden Aufruf von speziellen Methoden Geschieht bei der Erzeugung mittels new Diese speziellen Methoden heißen Konstruktoren Werden automatisch bei der Erzeugung (durch new) aufgerufen Bringen Instanzen in einen sicheren initialen Zustand
Umsetzung in C++ Konstruktoren: Methoden mit speziellem Namen und Rückgabetyp Name der Methode: Klassenname Rückgabetyp: Keiner, nicht einmal void Konstruktor sollte alle Attribute initialisieren (guter Stil) Syntax: Klassenname(Typ1 Name1, Typ2 Name2, ) { } Beispiel: Punkt(double x, double y) {...} Eine Klasse kann mehrere Konstruktoren haben Gleiches Prinzip wie Überladen von Methoden Ein Konstruktor kann als erstes anderen Konstruktor aufrufen Syntax: this(...parameter...); #4
#5 Beispiel Erzeugung von zwei Punkt- Instanzen in main Zeile 27 Kein Parameter an den Konstruktor Aufruf des parameter-losen Konstruktors aus Zeile 12 Dieser ruft Konstruktor in Zeile 17 auf Zeile 28 Zwei double-parameter Aufruf des Konstruktors in Zeile 17 Verwendung von this
Destruktoren Analog zu den Konstruktoren existieren Destruktoren Müssen manuell mittels delete aufgerufen werden Werden genau wie der Konstruktor definiert und mit einer führenden ~ gekennzeichnet Können nicht überladen werden, können keine Parameter akzeptieren und besitzen keinen Rückgabewert Dienen dem Freigeben von Ressourcen Gibt reservierten Speicher frei Schließt noch offene Dateien, Netzwerkverbindungen, etc. Häufige Fehlerursache Vorzeitiges Aufrufen des Destruktors (Undefiniertes Verhalten, Programmabstürze, ) Kein Aufrufen des Destruktors (Speicherleck Programmabsturz) Beispiel class Punkt { public: ~Punkt(); }; #6
Statische Methoden und Attribute
Statische Methoden Methoden verändern den Zustand einer Objektinstanz bzw. liefern Informationen über deren Zustand Manchmal praktisch, dieses Modell zu durchbrechen Main-Methode (Programmstart: keine Instanzen) Mathematische Funktionen (Wurzel, Sinus, Kosinus, etc.) Primitive Datentypen sind keine Objekte 1.sinus() funktioniert nicht new Sinus(1).getWert() zu großer Overhead Beispiel: #include <cmath> [ ] double ergebnis = cos (1.0); #8
Statische Methoden und Attribute Schlüsselwort static (unabhängig von Klasseninstanzen) Es gibt keine this -Referenz (keine Instanz verfügbar) Statische Elemente können nur andere statische Elemente verwenden Aufruf anderer statischer Methoden oder Verwenden statischer Variablen Statische Methoden Definition: static void statischemethode(...) {...} Verwendung: Klassenname::methodenname(Parameter) Alternativ: objekt.methodenname(parameter) Statische Attribute Definition: static int statischesattribut; Verwendung: Klassenname::attributname; Alternativ: objekt.attributname(parameter) #9
#10 Beispiel: Standardausgabe std::cout << Hallo << endl; Namespace std C++ Standard Bibliothek, Teil des ISO Standards Statische Methode cout Instanz der Klasse ostream (include <iostream>) Statische Methode endl Instanz der Klasse ostream (include <iostream>)
Beispiel: Instanzzähler #11
Beispiel: Instanzzähler #12
Beispiel statisch/nicht-statisch #13
Namespaces
Probleme großer Projekte Programme können aus vielen Klassen bestehen Verschiedene logische Funktionskomponenten Müssen nicht von einem Hersteller bzw. Programmierer stammen Normalerweise besteht ein Programm aus Teilen vieler Programmierer (externe Bibliotheken, Teams,...) Probleme Klassennamen doppelt vergeben Eindeutigkeit Unklare Zuordnung Funktionseinheit Klasse #15
Beispiel: Zwei Punkt -Klassen #16
#17 Beispiel: Zwei Punkt -Klassen Wie unterscheidet man die beiden Klassen im gleichen Programm? Eine Möglichkeit: umbenennen PunktRGB und PunktKoordinate Macht Programme oft schlechter lesbar (lange Namen) Beispiele (Windows API, Ungarische Notation) RtlWriteDecodedUcsDataIntoSmartLBlobUcsWritingContext ConvertSecurityDescriptorToStringSecurityDescriptor EapHostPeerQueryUIBlobFromInteractiveUIInputFields AccessCheckByTypeResultListAndAuditAlarmByHandle SetupRemoveInstallSectionFromDiskSpaceList
#18 Namespaces Alternative zu langen Namen Eingruppieren von Klassen in verschiedene Namensräumen Unterscheidung von Klassen durch Angabe des Namensraums Beispiel: Punkt aus Farbe vs. Punkt aus Mathe Analogie Klassennamen sind vergleichbar mit einem Vornamen Namespacename entspräche dann dem Familiennamen Namensraum Farbe Namensraum Mathe Punkt Attribute: - int rot; - int gruen; - int blau Methoden: Punkt Attribute: - double x; - double y; Methoden: - void setze(double x, double y); - void verschiebe(double dx, double dy); - void rotiere(double radians);
Namespaces: Beispiel #19
#20 Nested Namespaces Namespaces können auch ineinander geschachtelt werden Beispiel Punkt in Farbe Punkt in rgb in Farbe Punkt in version1 in rgb in Farbe Punkt in cmyk in Farbe Namensraum Farbe Punkt Namensraum rgb Namensraum cmyk Namensraum version1 Punkt Punkt Punkt
#21 Beispiel: Nested Namespaces Einzelne Bestandteile werden durch :: getrennt Beginnt bei der höchsten Hierarchiestufe int i; namespace A { namespace B } { } int i = 1; cout << A::B::i << endl; using namespace A::B; cout << i << endl; // Ambigous, use A::B::i or ::i
#22 Namespaces: Namenswahl Sinnvoll: Weltweit eindeutige Namen Üblich ist eine Schachtelung von Firmenname, Abteilung, Projektname, etc. Damit man Klassen aus verschiedenen Quellen ohne Namenskonflikte nutzen kann Beispiel: Klassen aus dem ITM namespace uniluebeck::itm Sinnvoll: Anhängen des Projektnamens Gesamt: uniluebeck::itm::programmieren::ws1314::uebung1::aufgabe2;
Namespaces: Beispiel #23
#24 Namespaces: Verwendung Zwei Varianten zur Verwendung von Klassen aus anderen Namespaces Angabe des voll-qualifizierten Namens (Klasse + Package) Farbe::rgb::Punkt* p = new farbe::rgb::punkt(); Schlüsselwort using für bestimmte Klassennamen Um die Angabe des voll-qualifizierten zu ersparen (Lesbarkeit) using namespace farbe:rgb:punkt;... Punkt p* = new Punkt();
Namespaces: Verwendung Kann natürlich auch gemischt verwendet werden Beispiel using namespace farbe:rgb:punkt;... Punkt p1 = new Punkt(); farbe::cmyk::punkt* p2 = new farbe::cmyk::punkt(); farbe::rgb::version1::punkt* p3 = new farbe::rgb::version1::punkt(); Es sind nach wie vor verschiedene Klassen Punkt* p1 = new farbe::cmyk::punkt(); //Fehler!!! #25
#26 Klassen ohne Namespace In welchem Namespace waren eigentlich unsere bisherigen Klassen? Kein Namespace: sog. Global Namespace Quasi ein Namespace ohne Namen Sollte man nur bei ganz kleinen Projekten nutzen Zitat aus dem Standard C++03 3.3.5 Namespace scope The outermost declarative region of a translation unit is also a namespace, called the global namespace. A name declared in the global namespace has global namespace scope (also called global scope).