Die Besonderheit von statischen Eigenschaften liegt darin, dass diese Eigenschaften zunächst für alle Objekte einer Klasse nur ein einziges Mal vorhanden sind. Desweiteren werden statische Eigenschaften standardmäßig immer mit 0 initialisiert und auf sie kann auch ohne Bezug auf ein bestimmtes Objekt zugegriffen werden (wenn sie public sind).
Um eine statische Eigenschaft zu definieren sind zwei Schritte erforderlich:
|
// Klassendefinition class Window { ... static short noOfWin; // Deklaration der statischen Eigenschaft ... }; // Definition der statischen Eigenschaft short Window::noOfWin = 0; |
|
|
Der Zugriff auf eine statische Eigenschaft aus einer Memberfunktion seiner Klasse heraus erfolgt gleich wie der Zugriff auf 'normale' Eigenschaften. Ist die statische Eigenschaft public, so kann auch von außerhalb der Klasse ohne Bezug auf ein Objekt auf diese Eigenschaft zugegriffen werden. In diesem Fall müssen Sie (wie unten angegeben) den Klassennamen vor den Eigenschaftsnamen stellen. Denken Sie immer daran: eine statische Eigenschaft besitzt keine Objektzugehörigkeit!
|
// Klassendefinition class Window { ... public: Window(); // ctor ~Window(); // dtor static short noOfWin; // Statische Eigenschaft ... }; // Definition der statischen Eigenschaft short Window::noOfWin = 0; // Zugriff aus Memberfunktion heraus Window::Window() { ... noOfWin++; // Anzahl Fenster inkrementieren } Window::~Window() { ... noOfWin--; // Anzahl Fenster dekrementieren } // main() Funktion main() { ... if (Window::noOfWin) // Falls bereits Fenster erstellt wurden .... } |
Im Beispiel sehen Sie einen Anwendungsfall für eine statische Eigenschaft. Die Eigenschaft noOfWin wird hier als Zähler für die Anzahl der erstellten Fensterobjekte verwendet. Da die statische Eigenschaften mit 0 initialisiert wird, braucht im Konstruktor dieser Zähler einfach nur um eins erhöht und im Destruktor wieder um eins erniedrigt werden. Selbstverständlich sollte in der Praxis dieser Zähler nicht, wie oben angegeben, public sein. Dies dient nur zur Demonstration des direkten Zugriffs auf eine statische Eigenschaft.
Sehen wir uns nun die statischen Memberfunktionen einer Klasse an. Statische Memberfunktionen besitzen eine Reihe von Einschränkungen:
Wozu statische Memberfunktionen trotz dieser vielen Einschränkungen dennoch nützlich sein können, das erfahren Sie gleich im Beispiel und der Übung. Doch sehen wir uns zunächst an, wie eine statische Memberfunktion definiert wird.
Um eine Memberfunktion als statische Memberfunktion zu definieren, wird bei ihrer Deklaration bzw. Definition innerhalb der Klasse das Schlüsselwort static vorangestellt. Wird die Memberfunktion außerhalb der Klasse definiert, so darf hier das Schlüsselwort static nicht mehr angegeben werden (siehe Beispiel).
|
// Klassendefinition class Window { ... static short noOfWin; // Statische Eigenschaft public: static short GetNoOfWin(); // Deklaration statische Memberfunktion ... }; // Definition der statischen Eigenschaft short Window::noOfWin = 0; // Definition der statischen Memberfunktion void Window::GetNoOfWin() { return noOfWin; } |
Beachten Sie aber, dass statische Memberfunktionen nur Zugriff auf statische Member haben!
Der Aufruf einer statischen Memberfunktion kann auf drei verschiedene Arten erfolgen:
Die letzten beiden Fälle sind im nachfolgenden Beispiel dargestellt.
|
// Klassendefinition class Window { ... // Definitionen wie oben }; // Definition der statischen Eigenschaft short Window::noOfWin = 0; // Definition der statischen Memberfunktion void Window::GetNoOfWin() { return noOfWin; } // main() Funktion int main() { Window myWin; short winCount; ... winCount = Window::GetNoOfWin(); winCount = myWin.GetNoOfWin(); ... } |
|
|
Titelfarbe: 0xff, Titel: Mein Fenster Titelfarbe: 0xff, Titel: Mein Fenster |
|
// Beispiel zu statischen Member // Zuerst Dateien einbinden #include <iostream> #include <string> using std::cout; using std::endl; using std::string; // Fensterklasse // Alle Fenster der Klassen haben eine gemeinsame // Titel- und Fensterfarbe aber unterschiedliche Titel class Window { static unsigned long titleColor; // Titelfarbe static unsigned long winColor; // Fensterfarbe string title; // Fenstertitel public: // ctor // Beachte: string ist ein Objekt und sollte deshalb // per Initialisiererliste initialisiert werden Window(const char* t): title(t) {} // Fenster darstellen void Draw() const; // statische Memberfunktionen zum Setzen der Farben static void SetTitleColor(unsigned char r, unsigned char g, unsigned char b); static void SetBackColor(unsigned char r, unsigned char g, unsigned char b); }; // Statische Eigenschaften der Window-Klasse definieren unsigned long Window::titleColor; unsigned long Window::winColor; // Fenstereigenschaften ausgeben void Window::Draw() const { cout << std::hex << std::showbase; cout << "Titelfarbe: " << titleColor; cout << ", Titel: " << title << endl; cout << "Fensterfarbe: " << winColor << endl; cout << std::dec << std::noshowbase; } // Titelfarbe setzen void Window::SetTitleColor(unsigned char r, unsigned char g, unsigned char b) { titleColor = (r<<16) + (g<<8) + b; } // Fensterfarbe setzen void Window::SetBackColor(unsigned char r, unsigned char g, unsigned char b) { winColor = (r<<16) + (g<<8) + b; } // main() Funktion int main() { // Fenster- und Titelfarbe setzen Window::SetBackColor(0x80,0x80,0x80); Window::SetTitleColor(0x00,0x00,0xff); // Zwei Fenster definieren Window myWin("Mein Fenster"); Window yourWin("Dein Fenster"); // und deren Eigenschaften ausgeben myWin.Draw(); yourWin.Draw(); // Fensterfarbe umsetzen // Beachte: Es wird die Fensterfarbe für alle Fenster // umgesetzt da die Fensterfarbe eine statische Eigenschaft ist myWin.SetBackColor(0x00,0x80,0xff); // Fenstereigenschaften erneut ausgeben cout << endl; myWin.Draw(); yourWin.Draw(); } |
Entwickeln Sie eine Klasse zur fiktiven Ansteuerung einer Ausgabeschnittstelle. Es sollen beliebig viele Objekte von dieser Klasse erstellt werden können, die über diese Schnittstelle Ausgaben tätigen können.
Da wir uns hier aber nicht mit der Ansteuerung einer realen Schnittstelle befassen wollen, sollen die Ausgaben auf die Schnittstelle als Bildschirmausgaben erfolgen. Für die Ausgabe auf die Schnittstelle ist eine entsprechende Memberfunktion vorzusehen, die als Parameter den auszugebenden Text erhalten soll.
Hat ein Objekt die Schnittstelle für eine Ausgabe erst einmal belegt, so belegt es die Schnittstelle so lange, bis es diese über eine ebenfalls zu schreibende Memberfunktion explizit wieder freigibt. Versuchen andere Objekte in der Zwischenzeit auf die belegte Schnittstelle etwas auszugeben, so erfolgt die Ausgabe einer Fehlermeldung.
Erzeugen Sie zwei Schnittstellen-Objekte. Geben Sie dann über das erste Objekt zweimal hintereinander einen beliebigen Text aus. Beide Ausgaben sollten ohne Fehlermeldung erfolgen.
Versuchen Sie dann eine Ausgabe über das zweite Objekt. Diese Ausgabe sollte blockiert sein, da das erste Objekt noch die Schnittstelle belegt hat.
Anschließend gibt das erste Objekt die Schnittstelle frei und das zweite Objekt versucht nun erneut zwei Ausgaben über die Schnittstelle vorzunehmen. Beide Ausgaben sollten jetzt ebenfalls erfolgreich durchgeführt werden, da das erste Objekt die Schnittstelle wieder freigegeben hat.
Bei richtiger Lösung werden Sie eine Ausgabe in etwa der nachfolgend dargestellten Form erhalten.
|
1. Schreiben von Objekt A |