Virtuelle Basisklassen

Probleme bei Mehrfach-Ableitung

Um den Einsatz von virtuellen Basisklassen zu veranschaulichen, sehen wir uns die folgende Klassenhierarchie an.

Oberste Basisklasse ist die Klasse Vehicle. Davon abgeleitet werden die beiden Klassen Electric und Petrol. Und aus diesen beiden Klassen wird eine neue Klasse Hybrid gebildet. Da sowohl Electric als auch Petrol von Vehicle abgeleitet sind, erben diese beiden Klassen die Eigenschaften von Vehicle. Wird aus Electric und Petrol eine neue Klasse gebildet, enthält die neue Klasse die Eigenschaften von Vehicle in zweifacher Ausführung, einmal von Electric und einmal von Petrol.

Virtuelle Basisklassen

Wird eine Klasse von mehreren Basisklassen abgeleitet, die wiederum von einer gemeinsamen Basisklasse abgeleitet sind, kann durch virtuelles Ableiten von der Basisklasse vermieden werden, dass die Eigenschaften der obersten Basisklasse mehrfach weitervererbt werden. In unserem Beispiel sind die Klassen Electric und Petrol virtuell von WinBase abzuleiten.

Um eine Klasse virtuell abzuleiten, wird vor oder nach dem Zugriffsrecht der Ableitung das Schlüsselwort virtual gestellt. Dabei ist zu beachten, dass nur die gemeinsame Basisklasse virtuell abgeleitet wird, im Beispiel die Klasse Vehicle.

#include <print>
#include <string>
#include <string_view>

class Vehicle
{
    std::string model;      // Modellbezeichnung
public:
    // ctor
    Vehicle(std::string_view _model): model(_model)
    {
        std::println(">>>ctor Vehicle");
    }
    // virtueller dtor
    virtual ~Vehicle()
    {
        std::println("<<<dtor Vehicle");
    }
};
class Electric: virtual public Vehicle
{
    unsigned short capacity;    // Batteriekapazitaet
public:
    Electric(std::string_view _model, unsigned short _capa):
        Vehicle(_model), capacity(_capa)
    {
        std::println(">>>ctor Electric");
    }
    virtual ~Electric()
    {
        std::println("<<<dtor Electric");
    }
};
class Petrol: virtual public Vehicle
{
    unsigned short tank;        // Tankinhalt
public:
    Petrol(std::string_view _model, unsigned short _tank):
        Vehicle(_model), tank(_tank)
    {
        std::println(">>>ctor Petrol");
    }
    virtual ~Petrol()
    {
        std::println("<<<dtor Petrol");
    }
};
class Hybrid: public Electric, public Petrol
{
public:
    Hybrid(std::string_view _model, unsigned short _tank,
           unsigned short _capa):
        Vehicle(_model), Electric(_model,_capa), Petrol(_model,_tank)
    {
        std::println(">>>ctor Hybrid");
    }
    virtual ~Hybrid()
    {
        std::println("<<<dtor Hybrid");
    }
};

int main()
{
    // Auto mit 60ltr Tank und 30kWh Accu
    Hybrid theCar("Mercedes",60,30);

}

>>>ctor Vehicle
>>>ctor Electric
>>>ctor Petrol
>>>ctor Hybrid
<<<dtor Hybrid
<<<dtor Petrol
<<<dtor Electric
<<<dtor Vehicle

Auf eine Besonderheit beim virtuellen Ableiten muss hingewiesen werden. Benötigt der Konstruktor der Basisklasse Parameter, ist der Konstruktor der abgeleiteten Klasse dafür verantwortlich, die Konstruktoren seiner Basisklassen aufzurufen, wobei der Konstruktor der 'obersten' Klasse zuerst aufzurufen ist (Zeile 53).