P
zuerst einmal sorgt
virtual void print() const = 0;
dafür, dass von der Klasse keine direkte Instanz erzeugt werden kann. Das heißt, es können nur abgeleitete Klassen erzeugt werden.
Ob der Konstuktor nun public oder protected ist, macht in diesem Fall keinen Unterschied, da Konstruktoren nicht vererbt werden und so dieser Konstuktor so oder so nur von abgeleiteten Klassen aufgerufen werden kann. Privat sein darf er nicht, da sonst abgeleitete Klassen keine Möglichkeit mehr hätten, ihren ListElem-Anteil zu initialisieren.
Destruktoren sollte bei Basisklassen immer virtuell gemacht werden, der grund dazu:
Nehmen wir an, di hast eine Basisklasse und eine abgeleitete Klasse:
class Foo
{
int a;
int b;
public:
Foo() : a(4), b(5) {};
~Foo() {};
};
class Bar : public Foo
{
largeClass * myPointer;
public:
Bar() : myPointer(new largeClass), Foo() {};
//hier wird neue Speicherplatz für ein Objekt von largeClass alloziiert
~Bar() { delete myPointer; }; //und hier wieder freigegeben
};
soweit schön und gut. Jetzt kommt Polymorphie ins spiel:
Foo * pf; //ein zeiger auf Foo
pf = new Bar(); //ist okay, Bar ist ja von Foo abgeleitet
//das Bar-Objekt hat jetzt seinen largeClass-zeiger
//mitsamt speicherplatz
delete pf; //ARGS
Beim delete wird natürlich der Destruktor von Foo aufgerufen, weil pf ja ein zeiger auf Foo ist. Der Destruktor von Bar wird nicht aufgerufen, und damit vergammelt unser largeClass-Speicherbereich bis zum jüngsten Gericht, ein Musterbeispiel von Speicherleck.
macht man aber den Destruktor von Foo virtuell, so wird bei "delete pf;" in der vtable des Objektes geguckt und gesehn, dass es ja den Bar-Destruktor gibt. Also kommt das normale Procedere: es werden sowohl von Bar als auch von Foo die Destruktoren aufgerufen, und alle sind glücklich.
im gcc gibts sogar eine Option, die eine Warnung ausspuckt, wenn man von einer Klasse mit nichtvirtuellem Destruktor ableitet:
gcc -WeffC++
(bin nicht ganz sicher ob großes oder kleines c)
Das aktiviert eben jene Warnung und überprüft ein paar weitere Stolpersteine, die in Scott Meyer's "effective C++" aufgeführt sind.