Mehrfachvererbung

In den bisherigen Beispielen wurde jede Klasse entweder von Grund auf neu geschaffen, oder sie wurde von genau einer Basisklasse abgeleitet.

In C++ ist es nun aber auch möglich, eine neue Klasse von mehreren Basisklassen abzuleiten (im Gegensatz zu Java beispielsweise).

Es ist allerdings schwer, dafür sinnvolle Beispiele zu finden, die vollständig ausformuliert in wenige Zeilen passen.

Hier wird nur das Prinzip gezeigt. Beispielsweise soll es ein Klasse Kran geben, die unter anderem durch ein Eigengewicht und eine maximale Last gekennzeichnet ist, sowie ein Klasse Fahrwerk.

Aus diesen beiden wird eine neue Klasse FahrbarerKran geschaffen, die sowohl von Kran als auch von Fahrwerk erbt:

class Kran
{
protected:
  double maxLast;
  double Eigengewicht;
  double Ausladung;

public:
  Kran( double maxLast, double Eigengewicht )
  {
    this->maxLast = maxLast;
    this->Eigengewicht = Eigengewicht;
  }

  virtual ~Kran(){}

  virtual double getEigengewicht() { return Eigengewicht; }

  virtual double getmaxLast() { return maxLast; }

  virtual double getAusladung() { return Ausladung; }
};

class Fahrwerk
{
protected:
  double maxLast;
  double Eigengewicht;

public:
  Fahrwerk( double maxLast,
            double Eigengewicht
            )
  {
    this->maxLast = maxLast;
    this->Eigengewicht = Eigengewicht;
  }

  virtual ~Fahrwerk(){}

  virtual double getEigengewicht() { return Eigengewicht; }

  virtual double getmaxLast() { return maxLast; }
};

class FahrbarerKran: public Fahrwerk, public Kran
{
public:
  FahrbarerKran( double maxLastFahrwerk,
                 double maxLastKran,
                 double EigengewichtFahrwerk,
                 double EigengewichtKran
                 )
    : Fahrwerk( maxLastFahrwerk, EigengewichtFahrwerk ),
      Kran( maxLastKran, EigengewichtKran )
  {
  }

  virtual ~FahrbarerKran(){}

  virtual double getEigengewicht()
  {
    return Kran::Eigengewicht + Fahrwerk::Eigengewicht;
  }

  virtual double getmaxLast()
  {
    // Die Last darf nicht größer werden als jeder der beiden
    // Werte:
    //    maxLast des Krans
    //    maxLast des Fahrwerks - Gewicht des aufgeschraubten Krans
    return ( Kran::maxLast>Fahrwerk::maxLast-Kran::Eigengewicht
              ? Fahrwerk::maxLast-Kran::Eigengewicht
              : Kran::maxLast
              );
  }
};

int main( int nargs, char **args )
{
  FahrbarerKran  Toefftoeff( 20000.0,  // Last Fahrwerk
                             20000.0,  // Last Kran
                             10000.0,  // Gewicht Fahrwerk
                             11000.0   // Gewicht Kran
                             );

  cout << "Gewicht : " << Toefftoeff.getEigengewicht() << endl;
  cout << "Last : " << Toefftoeff.getmaxLast() << endl;

  return 0;
} // main( int nargs, char **args )

Abbildung 4.2: Klassenhierarchie FahrbarerKran
\includegraphics[width=5cm]{FahrbarerKran1.ps}

Ein Objekt des Typs FahrbarerKran ist sowohl ein Fahrwerk, als auch ein Kran. Deshalb kann ein solches Objekt (Toefftoeff) sowohl an eine Funktion übergeben werden, die ein Fahrwerk erwartet, als auch an eine die einen Kran erwartet.

Innerhalb von FahrbarerKran existieren alle Elemente aus Fahrwerk ebenso wie alle Elemente aus Kran. Wenn die Namen kollidieren, dann muß mit dem jeweiligen Klassennamen und dem scope resolution operator nachgeholfen werden, um klarzumachen, was gemeint ist (Fahrwerk::maxLast-Kran::Eigengewicht).

Was passiert aber, wenn durch Mehrfachvererbung eine Basisklasse effektiv mehrfach eingebunden wird? Ein Beispiel wäre, sowohl Kran als auch Fahrwerk von einer gemeinsamen Basisklasse Maschine abzuleiten, die bereits ein Gewicht enthält. Dann könnte in Kran und Fahrwerk das entsprechende Feld entfallen:

class Maschine
{
protected:
  double Eigengewicht;

public:
  Maschine( double Eigengewicht )
  {
    this->Eigengewicht = Eigengewicht;
  }

  virtual ~Maschine(){}

  virtual double getEigengewicht() { return Eigengewicht; }

};

class Fahrwerk: public Maschine
{
protected:
  double maxLast;

public:
  Fahrwerk( double maxLast, double Eigengewicht )
    : Maschine( Eigengewicht )
  {
    this->maxLast = maxLast;
  }

  virtual ~Fahrwerk(){}

  virtual double getEigengewicht() { return Eigengewicht; }

  virtual double getmaxLast() { return maxLast; }
};



class Kran: public Maschine
{
protected:
  double maxLast;
  double Ausladung;

public:
  Kran( double maxLast, double Eigengewicht )
    : Maschine( Eigengewicht )
  {
    this->maxLast = maxLast;
  }

  virtual ~Kran(){}

  virtual double getEigengewicht() { return Eigengewicht; }

  virtual double getmaxLast() { return maxLast; }

  virtual double getAusladung() { return Ausladung; }
};

class FahrbarerKran: public Fahrwerk, public Kran
{
public:
  FahrbarerKran( double maxLastFahrwerk,
                 double maxLastKran,
                 double EigengewichtFahrwerk,
                 double EigengewichtKran
                 )
    : Fahrwerk( maxLastFahrwerk, EigengewichtFahrwerk ),
      Kran( maxLastKran, EigengewichtKran )
  {
  }

  virtual ~FahrbarerKran(){}

  virtual double getEigengewicht()
  {
    return Kran::Eigengewicht + Fahrwerk::Eigengewicht;
  }

  virtual double getmaxLast()
  {
    // Die Last darf nicht größer werden als jeder der beiden
    // Werte:
    //    maxLast des Krans
    //    maxLast des Fahrwerks - Gewicht des aufgeschraubten Krans
    return ( Kran::maxLast>Fahrwerk::maxLast-Kran::Eigengewicht
              ? Fahrwerk::maxLast-Kran::Eigengewicht
              : Kran::maxLast
              );
  }
};


int main( int nargs, char **args )
{
  FahrbarerKran  Toefftoeff( 20000.0,  // Last Fahrwerk
                             20000.0,  // Last Kran
                             10000.0,  // Gewicht Fahrwerk
                             11000.0   // Gewicht Kran
                             );

  cout << "Gewicht : " << Toefftoeff.getEigengewicht() << endl;
  cout << "Last : " << Toefftoeff.getmaxLast() << endl;

  return 0;
} // main( int nargs, char **args )

In diesem Fall enthält sowohl Kran als auch Fahrwerk jeweils eine Maschine. In FahrbarerKran sind also zwei Maschinen enthalten!

Abbildung 4.3: Klassenhierarchie FahrbarerKran mit 2 Maschinen
\includegraphics[width=5cm]{FahrbarerKran2Maschinen.ps}

Wenn man stattdessen wünscht, daß eine Klasse, die von Kran und Fahrwerk erbt, nur eine Maschine ist, dann müssen Kran und Fahrwerk von Maschine virtuell erben:

class Fahrwerk: public virtual Maschine
{
  //...
};

class Kran: public virtual Maschine
{
  //...
};

class FahrbarerKran: public Fahrwerk, public Kran
{
  //...
};

Dadurch wird bei einer folgenden Mehrfachvererbung nur eine Maschine erscheinen; dementsprechend gibt es auch nur ein gemeinsames Eigengewicht:

class Maschine
{
protected:
  double Eigengewicht;

public:
  Maschine( double Eigengewicht )
  {
    this->Eigengewicht = Eigengewicht;
  }

  virtual ~Maschine(){}

  virtual double getEigengewicht() { return Eigengewicht; }

};

class Fahrwerk: public virtual Maschine
{
protected:
  double maxLast;

public:
  Fahrwerk( double maxLast, double Eigengewicht )
    : Maschine( Eigengewicht )
  {
    this->maxLast = maxLast;
  }

  virtual ~Fahrwerk(){}

  virtual double getEigengewicht() { return Eigengewicht; }

  virtual double getmaxLast() { return maxLast; }
};



class Kran: public virtual Maschine
{
protected:
  double maxLast;
  double Ausladung;

public:
  Kran( double maxLast, double Eigengewicht )
    : Maschine( Eigengewicht )
  {
    this->maxLast = maxLast;
  }

  virtual ~Kran(){}

  virtual double getEigengewicht() { return Eigengewicht; }

  virtual double getmaxLast() { return maxLast; }

  virtual double getAusladung() { return Ausladung; }
};

class FahrbarerKran: public Fahrwerk, public Kran
{
public:
  FahrbarerKran( double maxLast,
                 double Eigengewicht
                 )
    : Maschine( Eigengewicht ),
      Fahrwerk( maxLast, Eigengewicht ),
      Kran( maxLast, Eigengewicht )
  {
  }

  virtual ~FahrbarerKran(){}

  virtual double getEigengewicht()
  {
    return Eigengewicht;
  }

  virtual double getmaxLast()
  {
    // Die Last darf nicht größer werden als jeder der beiden
    // Werte:
    //    maxLast des Krans
    //    maxLast des Fahrwerks - Gewicht des aufgeschraubten Krans
    return Kran::maxLast;
  }
};


int main( int nargs, char **args )
{
  FahrbarerKran  Toefftoeff( 9000.0,   // Last
                             21000.0   // Gesamtgewicht
                             );

  cout << "Gewicht : " << Toefftoeff.getEigengewicht() << endl;
  cout << "Last : " << Toefftoeff.getmaxLast() << endl;

  return 0;
} // main( int nargs, char **args )
Dieses Beispiel ist insofern schlecht konstruiert, als Maschine::Eigengewicht mehrfach initialisiert wird.

Aber das wesentliche der virtuellen Vererbung ist ersichtlich: die virtuelle geerbte Basisklasse ist nur noch einfach vorhanden.

Abbildung 4.4: Klassenhierarchie FahrbarerKran mit einer Maschine
\includegraphics[width=5cm]{FahrbarerKran1Maschine.ps}

AnyWare@Wachtler.de