Historie der Frage:
Polymorphismus wurde zu einer der Schlüsselmerkmale der objektorientierten Programmierung bereits in der frühen Entwicklung von C++. Ziel ist es, auf Objekte über eine Basisschnittstelle zuzugreifen, ohne sich um den konkreten Typ zu kümmern. Dies erweitert die Ausdruckskraft und Flexibilität des Codes erheblich.
Problem:
Ohne Polymorphismus wird der Code unflexibel: Es ist notwendig, die Typen der Objekte explizit zu erkennen, switch/case zu verwenden und manuelle Typumwandlungen durchzuführen. Dies erschwert die Wartung und Erweiterung der Anwendung — das Hinzufügen neuer Typen wird kostspielig oder unmöglich, ohne den vorhandenen Code zu ändern.
Lösung:
In C++ wird Polymorphismus durch die Verwendung von virtuellen Funktionen erreicht. Klassen deklarieren virtuelle Methoden, und Abkömmlinge implementieren diese. Die Basisklasse bietet eine gemeinsame Schnittstelle, während die tatsächlichen Aktionen vom tatsächlichen Typ des Objekts abhängen, auf das der Zeiger oder die Referenz verweist.
Codebeispiel:
#include <iostream> class Animal { public: virtual void speak() const { std::cout << "Some animal sound "; } virtual ~Animal() {} }; class Dog : public Animal { public: void speak() const override { std::cout << "Woof! "; } }; void makeSound(const Animal& a) { a.speak(); } int main() { Dog dog; makeSound(dog); // Gibt aus: Woof! } }
Schlüsselfunktionen:
virtual deklariert werden.override — dies erhöht die Sicherheit des Codes.Was passiert, wenn der Destruktor der Basisklasse nicht virtuell deklariert wird?
Das Löschen des Objekts über einen Zeiger auf die Basisklasse ruft nur den Destruktor der Basisklasse auf, der Destruktor der abgeleiteten Klasse wird nicht aufgerufen, was zu Ressourcenlecks führt.
Codebeispiel:
class Base { public: ~Base() { /*...*/ } }; class Derived : public Base { public: ~Derived() { /*...*/ } }; Base* obj = new Derived(); delete obj; // UB: Derived::~Derived wird nicht aufgerufen
Kann man nur teilweise virtuelle Methoden deklarieren und den Destruktor nicht virtuell lassen?
Nein, wenn die Klasse polymorph ist (es gibt mindestens eine virtuelle Funktion), muss der Destruktor virtuell sein, um Gedächtnis- oder Ressourcenlecks zu vermeiden.
Funktionieren virtuelle Funktionen für Mitglieder, die als static deklariert sind?
Nein, statische Mitglieder einer Klasse können nicht virtuell sein, da sie nicht einem bestimmten Objekt angehören, und es gibt keinen Mechanismus für dynamisches Binden für sie.
override in der abgeleiteten Klasse zu kennzeichnen, was zu einer fehlerhaften Überschreibung der Methode führt.Eine sehr große Hierarchie von Geräteklassen, jede abgeleitete Klasse verwaltet ihre Ressource (z.B. eine offene Datei), aber der Destruktor der Basisklasse ist nicht virtuell. Bei der Löschung über einen Zeiger auf die Basisklasse werden die Ressourcen nicht freigegeben.
Vorteile: Das Projekt wird schnell aufgebaut, minimaler virtueller Aufruf.
Nachteile: Speicherlecks, falsche Zerstörung. Extrem schwierig zu warten und weiterzuentwickeln.
Eine durchdachte polymorphe Hierarchie, die Basisklasse hat virtuelle Funktionen und einen virtuellen Destruktor. Das Schlüsselwort override und die Prinzipien von RAII werden verwendet.
Vorteile: Sichere Handhabung von Ressourcen, einfache Erweiterung, Testbarkeit.
Nachteile: Etwas geringere Leistung aufgrund von vtable-lookup, Impfung gegen "over-engineering", wenn Vererbung ohne Notwendigkeit angewendet wird.