A
JDieskau schrieb:
Die Erleuchtung kommt vielleicht noch wenn ich erstmal verstanden hab was dieses virtual ist
Damit solltest du dich befassen, unabhängig welche Lösung du verwendest, da virtual in der OOP nicht grade unwichtig ist, sobald es um Vererbung geht.
Hier ein kurzes Beispiel was ich anschließend erkläre:
#include <iostream>
#include <vector>
#include <boost/shared_ptr.hpp>
class Base
{
public:
// Bei Basisklasse sollte in der Regel Destruktor immer virtuell sein
virtual ~Base() {}
// Dies ist eine rein virtuelle Funktion, komme mit der Erklärung später
virtual void foo() = 0;
};
class A : public Base
{
public:
void foo()
{
std::cout << "A::foo()\n";
}
};
class B : public Base
{
public:
void foo()
{
std::cout << "B::foo()\n";
}
};
int main()
{
std::vector<boost::shared_ptr<Base> > liste;
liste.push_back(boost::shared_ptr<Base>(new A()));
liste.push_back(boost::shared_ptr<Base>(new B()));
liste.push_back(boost::shared_ptr<Base>(new B()));
liste.push_back(boost::shared_ptr<Base>(new A()));
for(std::vector<boost::shared_ptr<Base> >::const_iterator pos = liste.begin(), end = liste.end();
pos != end; ++pos)
{
(*pos)->foo();
}
int a;
std::cin >> a;
}
Ein kleines Vorwort, da du vermutlich boost::shared_ptr nicht kennst: Dies ist ein sogenannter Smartpointer, der sich darum kümmert das am Schluß delete aufgerufen wird (er macht noch mehr, aber für das Beispiel reicht es zu wissen das es mir nur darum geht das ich nicht anschließend die Elemente händisch löschen muss). Das Beispiel hätte auch mit einen std::vector<Base*> geklappt, nur müsste man dann wie gesagt an das delete denken...
Nun aber zum Eigentlichen: Ich habe eine Basisklasse Base und zwei davon abgeleitete Klassen A und B. Base besitzt als rein virtuelle Methode "void foo()", die von den abgeleiteten Klassen überschrieben wird. Zugreifen tue ich über Zeiger auf die Basisklasse, sprich der konkrete Typ ist zum Zeitpunkt des aufrufend von foo() dem Anwender unbekannt. Nun kommt der Mechanismus zum tragen der mit virtual zu tun hat. virtual sorgt davor das die "richtige" Methode aufgerufen wird (Um genau zu sein: die Methode im Vererbungsbaum die am nächsten am konkreten Objekt ist, dies ist wichtig falls es über mehr als 2 Ebenen geht).
Nun gibt es zwei möglichkeiten virtual zu verwenden:
a) Virtuelle Methode:
Diese Methode hat eine Definition, sofern in der abgeleiteten Klasse diese Methode nicht überschrieben wird, wird diese ausgeführt (Sprich: dies ist dann sinnvoll wenn du weist wie der Regelfall abzuarbeiten ist, aber auch eine andere Variante zulassen möchtest).
b) Rein Virtuelle Methode:
Diese Methode hat nur eine Deklaration (mit einem = 0 am Ende). Von einer Klasse die rein virtuelle Methoden bestitzen, können keine Instanzen gebildet werden (das gleiche gilt für abgeleitete Klassen, die diese Methoden nicht überschreiben). Dies ist dann sinnvoll wenn die Klasse entweder als reine Schnittstelle dient (entspricht dem Interface in Java) oder wenn es nicht möglich wäre hierfür eine sinnvolle Behandlung zu schreiben, ohne das wissen der abgeleiteten Klassen zu haben.
Ein Sonderfall: Man kann auch den Destruktor rein virtuell deklarieren, muss diesen aber dennoch definieren. Dies ist dann sinnvoll, wenn die Klasse als solche nicht instanzierbar sein soll, aber es keine andere rein virtuelle Methode gibt.
cu André