Abstrakte Klassen und C ++

Abstrakte Klassen und C ++ - Dummies

C ++ unterstützt late binding , das ist, wenn es einen Methodenaufruf basierend auf der Laufzeit auflöst Typ (oder dynamischer Typ) des Zielobjekts anstelle seines deklarierten Typs (oder statischen Typs). Dies wird im folgenden C ++ - Code-Snippet veranschaulicht:

 #include using namespace std; Klasse Ofen {public: virtual void cook () {cout << "Kochen mit Ofen" << endl;}}; Klasse MicrowaveOven: public Oven {public: virtueller void cook () {cout << "Kochen mit einer Mikrowelle" << endl;}}; Leere vorbereitenMahlzeit (Ofen & Ofen) {Backofen. cook ();} 

In der Funktion prepareMeal () den Aufruf von oven. cook () kann an Oven:: cook () oder MicrowaveOven:: cook () übergeben werden, abhängig von der Laufzeit (dem "tatsächlichen") Typ des Ofenobjekts, das übergeben wurde.

Das virtuelle Schlüsselwort ist hier kritisch. Ohne sie würde die cook () -Methode auf Grundlage des Kompilierzeittyps früh gebunden werden und Oven:: cook () jedes Mal aufrufen. Einmal in der Klasse Oven als virtuell deklariert, wird angenommen, dass die Methode in jeder Unterklasse virtuell ist, aber es schadet nicht, die Deklaration zu wiederholen, damit die Leser sie verstehen.

Das folgende einfache Programm demonstriert dieses Prinzip in der Praxis:

 int main () {Backofen; prepareMeal (Ofen); MikrowelleOfen mo; zubereitenMahl (mo); return 0;} 

In diesem Programm erzeugt der Aufruf von cook () je nach Ofentyp zwei verschiedene Ausgänge:

 Kochen mit einem Ofen Kochen mit einem Mikrowellenherd 

Das ist nicht immer der Fall, dass eine Methode in der Basisklasse definiert werden kann. Betrachten Sie den Ofenfall genauer. Es gibt eine Reihe von verschiedenen Arten von Öfen - herkömmliche Öfen, Konvektionsöfen und Mikrowellenöfen - aber man könnte argumentieren, dass es keinen tatsächlichen Ofen gibt, der nicht zu einer dieser Unterklassen gehört. Sie können vielleicht sagen, wie die verschiedenen Ofentypen die Kochoperation ausführen - das heißt, was ein ConventionalOven:: cook () und ein MicrowaveOven:: cook () tun sollten, kann definiert werden. Es ist wahrscheinlich nicht möglich zu definieren, welche Aktionen Oven:: cook () ausführen soll.

Sie können nicht einfach Ofen:: cook () in einer stark typisierten Sprache wie C ++ nicht deklariert lassen. Sie können jedoch als deklarieren, aber nicht implementiert lassen , wenn keine Implementierung vorhanden ist. Dazu benutzt man die folgende merkwürdige Syntax:

 class Oven {public: virtual void cook () = 0;}; 

Dieser Code deklariert eine Methode Oven:: cook (), die spät gebunden wird, aber die Methode nicht implementiert. In der Tat geht es weiter, indem er sagt, dass die Methode nicht implementiert wird. In C ++ wird ein solches Verfahren als reines virtuelles bezeichnet. C ++ - Programmierer verwenden auch den in vielen anderen stark typisierten Computersprachen bevorzugten Begriff: abstract .Die Ofenklasse soll abstrakt sein.

Eine Zusammenfassung stellt eine Eigenschaft dar, von der Sie wissen, dass sie über eine Klasse verfügt, aber nicht weiß, wie sie in der aktuellen Klasse eindeutig implementiert werden soll.

Eine Klasse ist abstrakt, wenn sie eine oder mehrere reine virtuelle Methoden enthält. Die Bedeutung davon ist, dass Sie keine abstrakte Klasse instanziieren können. Somit ist Folgendes nicht mehr erlaubt:

 int main () {Backofen; prepareMeal (Ofen); return 0;} 

Der Grund dafür ist ganz einfach: Wenn Sie ein Objekt der Klasse Ofen erstellt haben und dann versucht haben, den Ofen aufzurufen. cook (), was sollte der Compiler machen?

Auf einer eher philosophischen Ebene ist es gut zu sagen, dass es einen gebräuchlichen Begriff namens Ofen gibt, der konventionelle Öfen und Mikrowellenherde und Konvektionsöfen beschreibt. Dieser Begriff Ofen ist ein übliches Konzept, weil er die Ähnlichkeiten in all diesen Unterklassen verbindet. Aber es gibt keinen Fall eines Ofens, der nicht eine der Unterklassen von Oven ist.

Eine Unterklasse einer abstrakten Klasse ist selbst abstrakt, bis alle reinen virtuellen Methoden durch nicht abstrakte (dh konkrete ) Versionen außer Kraft gesetzt wurden. Somit ist die Klasse MicrowaveOven im vorherigen Code-Snippet nicht abstrakt - selbst wenn Oven abstrakt wäre - weil sie cook () mit einer eigenen konkreten Version überschreibt.

Beachten Sie, dass nichts falsch mit der Funktion prepareMeal () ist, die wie folgt definiert ist:

 void prepareMeal (Ofen & Ofen) {oven. cook ();} 

Obwohl das Argument als Ofen deklariert ist, kann es nur mit einer Unterklasse des Ofens aufgerufen werden, z. B. MicrowaveOven oder ConventionalOven, für die cook () definiert ist.