C++ Kurs

Virtuelle Basisklassen

Die Themen:

Probleme bei Mehrfach-Ableitung

Um die Bedeutung von virtuellen Basisklassen zu veranschaulichen, sehen wir uns zunächst einmal die nachfolgende Klassenhierarchie an. Oberste Basisklasse ist die Klasse CWinBase. Davon abgeleitet werden die beiden Klassen CFrame (Implementierung eines Fensters mit Rahmen) und die Klasse CMenu (Implementierung eines Fenstermenüs). Aus diesen beiden Klassen wird dann eine neue Klasse CWindow gebildet, die ein Rahmenfenster mit Menü darstellen soll.

Ableitung von einer gemeinsamen Basisiklasse

Wenn wir uns diese Ableitungen einmal genau anschauen, dann sollten jetzt leichte Bedenken an dieser Klassenhierarchie auftreten. Da sowohl CFrame als auch CMenu von CWinBase abgeleitet sind, erben diese beiden Klassen natürlich die Eigenschaften von CWinBase. Wird nun aus CFrame und CMenu eine neue Klasse gebildet, so enthält die neue Klasse die Eigenschaften von CWinBase in zweifacher Ausführung, einmal von CFrame und einmal von CMenu. Und das ist bestimmt nicht das, was mit der Ableitung erreicht werden sollte. Das nachfolgende Bild veranschaulicht diesen Sachenverhalt nochmals.

Ableitung von einer gemeinsamen Basisklasse

Virtuelle Basisklassen

Und auch in diesen Fall hilft uns das Schlüsselwort virtual weiter. Wird eine Klasse von mehreren Basisklassen abgeleitet, die wiederum selbst von einer gemeinsamen Basisklasse abgeleitet sind, so kann durch virtuelles Ableiten von der Basisklasse vermieden werden, dass die Eigenschaften der obersten Basisklasse mehrfach weitervererbt werden. In unserem Beispiel müssen also die Klassen CFrame und CMenu virtuell von CWinBase abgeleitet werden.

Virtuelle Ableitungen

Virtuelle Basisklassen und Konstruktore

Sehen wir uns das virtuelle Ableiten in der Praxis an. Um eine Klasse virtuell abzuleiten, wird vor dem Zugriffrecht der Ableitung das Schlüsselwort virtual gestellt. Dabei ist zu beachten, dass nur die gemeinsame Basisklasse virtuell abgeleitet wird, im Beispiel also die Klasse CWinBase.

PgmHeader// Oberste Basisklasse
class CWinBase
{....};
// 1. virtuell abgeleitete Klasse
class CFrame: virtual public CWinBase
{....};
// 2. virtuell abgeleitete Klasse
class CMenu: virtual public CWinBase
{....};
// Endgültige Klasse
class CWindow: public CFrame, public CMenu
{....};

Auf eine Besonderheit beim virtuellen Ableiten muss noch hingewiesen werden. Bei einer normalen Ableitung ruft der Konstruktor einer abgeleiteten Klasse die Konstruktoren seiner Basisklassen auf. Bei virtuell abgeleiteten Klassen trifft dies aber nur dann zu, wenn die Basisklassen einen Standard-Konstruktor besitzen. Benötigt der Konstruktor der Basisklasse jedoch Parameter, so ist der Konstruktor der abgeleiteten Klasse selbst dafür verantwortlich, die Konstruktore seiner Basisklassen aufzurufen. Für unser Beispiel ergibt sich damit der unten dargestellte Konstruktor der Klasse CWindow.

PgmHeaderCWindow::CWindow(...):
   CWinBase(...), CFrame(...), CMenu(...)   // Aufrufe der ctors
{
    ....
}

Für die Aufruf-Reihenfolge der Konstruktoren gilt, dass zuerst der Konstruktor der obersten Basisklasse ausgeführt wird und danach die Konstruktoren der nachfolgenden Basisklassen und zwar in der Reihenfolge, in der die Basisklassen bei der Klassendefinition angegeben wurden. Diese Reihenfolge ist auch bei der Initialisiererliste der 'untersten' Klasse einzuhalten, da ansonsten je nach Compiler eventuell eine Reihe Warnungen ausgegeben wird.

BeispielUnd hier geht's zum Beispiel. Auf eine Übung verzichten wir an dieser Stelle.