robert filatow logo
deadly diamond of death thumbnail

Deadly diamond of death in C++ – Probleme bei der Mehrfachvererbung

Einleitung

Der Deadly Diamond of Death(übersetzt: TÖDLICHES DIAMANTEN PROBLEM DES TODES) bzw. das “diamond problem” beschreibt das Problem, welches entsteht wenn zwei Klassen von der gleichen Basis erben und eine Klasse von den beiden Klassen erbt. Dadurch wird die Basisklasse mehrfach vererbt und es entsteht eine Mehrdeutigkeit.

Und nein den Namen habe ich mir nicht ausgedacht, das heißt wirklich so.

Dieses Problem gilt nicht nur für C++, sondern für alle Sprachen, die Mehrfachvererbung unterstützen.

Du solltest wissen

  • Wie Vererbung bei Objektorientierter Programmierung funktioniert.
  • Wie Polymorphismus funktioniert

Was ist das Problem?

Das Problem beim DEADLY DIAMOND OF DEATH ist, dass es zu einer Mehrdeutigkeit (auf Unideutsch: zu einer Ambiguität) führt.

Wie in dem Bild, wird die Basisklasse einmal von Links und einmal von Rechts geerbt. Da die Klasse Verbunden von Links und Rechts erbt wird Basis zweimal vererbt. Möchte man nun eine Methode von Verbunden abrufen, welche von der Basisklasse stammt, dann weiß der Compiler nicht welche Methode man meint, da die Methoden der Basisklasse jetzt mehrfach vorliegen. Alles etwas verwirrend, keine Sorge ich erkläre dir das jetzt an einem Beispiel.

Beispiel

Nehmen wir an, wir haben eine Basisklasse Saeugetier mit einer Methode essen(). Dann eine Klasse Mensch, welcher sprechen() kann und eine Klasse Fledermaus die fliegen() kann. Zuletzt haben wir eine Klasse Manbat, welcher sowohl essen(), sprechen() und fliegen() kann und sich mit Batman prügelt.

#include <iostream>

class Saeugetier{
   public:
      void essen(){
          std::cout << "Ab sofort steht wieder Fleisch auf den Speiseplan" << std::endl;
      }
};

class Mensch : public Saeugetier{
   public:
      void sprechen(){
          std::cout << "Ich kann sprechen" << std::endl;
      }
};

class Fledermaus: public Saeugetier{
   public:
      void fliegen(){
         std::cout << "I believe I can fly" << std::endl;
      }
};

class Manbat : public Mensch, public Fledermaus{
};
int main()
{
    Manbat manbat;
    manbat.sprechen();
    manbat.fliegen();
    //manbat.essen(); //error: request for member 'essen' is ambiguous
    return 0;
};

Ich kann sprechen
I believe I can fly

Process returned 0 (0x0) execution time : 0.025 s
Press any key to continue.

manbat.sprechen() und manbat.fliegen() funktioniert ohne Probleme.
Aber manbat.essen() führt zu folgender Fehlermeldung:

error: request for member ‘essen’ is ambiguous

Manbat erbt von Mensch und von Fledermaus. Das führt in C++ dazu, dass unsere Basis Saeugetier zweimal in Manbat vorhanden ist. Alle Member von Saeugetier liegen nun doppelt vor. Wollen wir nun essen() von einem Manbat Objekt abrufen, dann würde der Compiler nicht wissen welches, essen() gemeint ist.

Lösung: virtuelle Basisklassen

Es gibt mehrere Lösungen für das Problem. Da ich jedoch den Beitrag heute noch fertig schreiben will erkläre ich dir nur eine anständige Lösung.

Theoretisch könnten wir eine eigene Funktion essen() für Manbat definieren. Aber dann würden wir den Code doppelt schreiben müssen und den Zweck der Vererbung verfehlen.

class Manbat : public Mensch, public Fledermaus{
    public:
      void essen(){
          std::cout << "Ab sofort steht wieder Fleisch auf den Speiseplan" << std::endl;
      }
};

Bei diesem Beispiel wäre das kein großer Zusatzaufwand, aber beim Programmieren im “Großen” könnte es zu Problemen führen.

Was wir statt dessen machen können, ist es virtuelle Basisklassen zu deklarieren. Dafür müssen wir bei den Klassen die von der Basisklasse ableiten das Schlüsselwort virtual dransetzen.

class Mensch : virtual public Saeugetier{
   public:
      void sprechen(){
          std::cout << "Ich kann sprechen" << std::endl;
      }
};

class Fledermaus: virtual public Saeugetier{
   public:
      void fliegen(){
         std::cout << "I believe I can fly" << std::endl;
      }
};

Nun erzeugt der Compiler nur ein Subobjekt von Saeugetier. Da der Compiler dafür zuständig ist, passiert das zur Übersetzungszeit und nicht zur Laufzeit.

Zusammenfassung

  • Das “diamond problem” beschreibt das Problem, welches entsteht wenn zwei Klassen von der gleichen Basis erben und eine Klasse von den beiden Klassen erbt. Dadurch wird die Basisklasse mehrfach vererbt und es entsteht eine Mehrdeutigkeit.
  • Die Lösung dafür, ist es die Klassen – die von der Basis ableiten – als virtual zu deklarieren.

Hat dir der Inhalt gefallen?

Falls du mehr zu Themen der Informatik lesen willst, kannst du die Suche dafür verwenden:


Du bist der Meinung, das war der Beste Beitrag zum Thema Informatik den du jemals gelesen hast? Dann ist die einzig logische Schlussfolgerung, diesen Beitrag mit deinen Kommilitonen zu teilen. Oder auch nicht mach was du willst, ich bin nicht dein Dad.

TAGS

© 2023. All rights reserved. Website made by Robert Filatow