MV "Diamond of death" - auch gefährlich bei rein abstrakten Klassen?



  • Servus,

    ich stehe gerade vor einer ziemlich fundamentalen Designentscheidung und habe entdeckt, dass ich dabei bin einen "diamond of death" zu konstruieren. Ich meine jedoch, dass er ungefährlich ist, da er in rein abstrakten Klassen (pure virtual Interfaces ohne membervariablen) auftritt.

    Dennoch würde ich gerne mal eure Meinung hören.

    Folgende Situation: Es gibt ein Klassentemplate A, das die Arbeit macht. Einige seiner Memberfunktionen sind völlig unabhängig vom konkreten Typ. Daher habe ich eine interface-Klasse IA mit rein virtuellen Funktionen, von der das Klassentemplate A erbt. Das erlaubt mir, die Instanzen in einem ptr_container von Interface-Pointern zu speichern und alles, was Typ-unabhängig ist, damit zu machen.

    Jetzt habe ich aber weitere Funktionalität, die in A nichts zu suchen hat und auch im A-Interface nicht. Deshalb erbt B von A und fügt die Funktionalität hinzu, und ein neues Interface IB beschreibt wiederum die Typ-unabhängige-Funktionalität.
    Und da entsteht ein "Diamond of death".

    Aber ein paar Zeilen Code zeigen mehr als tausend Worte:

    // Interface to class A
    class IA{
    public:
    virtual void foo() = 0;
    // hier gibts KEINE Membervariablen
    }
    
    // template class A:
    template <typename T>
    class A<T>: public Base<T>, public IA, private boost::noncopyable {
    public: virtual void foo() { dosomething(); }
    // hier gibt es membervariablen
    }
    

    Dann gibts die abgeleiteten Klassen:

    // Interface to B
    class IB : public IA {
    public: virtual void bar() = 0;
    // hier gibt es KEINE membervariablen
    }
    
    // class B
    template <typename T>
    class B<T>: public A<T>, public IB
    {
    public: virtual void bar() {doSomethingElse();}
    // hier gibt es Membervariablen
    }
    

    Jetzt entsteht ein diamond von B nach IA, nämlich:
    IA<-A<-B und andererseits IA<-IB<-B

    Da IA und IB abstrakte Klassen ohne Membervariablen sind, halte ich das für nicht gefährlich, lasse mich aber gerne von Euch eines besseren belehren.

    Gruß,
    Phil



  • Was soll dann passieren, wenn ein IA eine Funktion aufruft, welche in A und IB überschrieben wird?

    btw:
    Es gibt noch die virtuelle Vererbung, damit du keine zwei A Objekte pro B hast.



  • drakon schrieb:

    Was soll dann passieren, wenn ein IA eine Funktion aufruft, welche in A und IB überschrieben wird?

    Genau das passiert ja nicht, da in IB keine Funktionen definiert werden, die schon in IA definiert sind. Wäre ja auch quatsch.
    Mit IA kann man Funktionen aufrufen, die in A definiert sind, und mit IB kann man Funktionen aufrufen, die in B oder A definiert sind.

    btw:
    Es gibt noch die virtuelle Vererbung, damit du keine zwei A Objekte pro B hast.

    Wieso soll B zwei A-Objekte enhalten? Es enthielte höchstens zwei IA-Objekte. Aber da die keine Membervariablen haben, ist virtuelle Verebung unnötig, dachte ich (entsprechend Meyers, Kapitel 6, Tipp40 zu MI).



  • Genau das passiert ja nicht, da in IB keine Funktionen definiert werden, die schon in IA definiert sind. Wäre ja auch quatsch.

    Das scheine ich bei dir überlesen zu haben..

    Wieso soll B zwei A-Objekte enhalten? Es enthielte höchstens zwei IA-Objekte.

    Jup, meinte IA.

    aber da die keine Membervariablen haben, ist virtuelle Verebung unnötig, dachte ich (entsprechend Meyers, Kapitel 6, Tipp40 zu MI).

    Da steht aber nichts davon, dass virtuelle Vererbung nicht nötig ist, wenn die Basis keine Daten enthält.. 🙄
    Probier sonst mal das hier:

    IA* = new B;
    

    Dann siehst du, dass es mehrere IA's gibt.



  • Ich habe mein Design jetzt dahingehend geändert dass ich keine Mehrfachvererbung mehr an dieser Stelle habe...
    Auslösend war die Erkenntnis, dass es ein Anzeichen für schlechtes Design ist, wenn man länger als 15 Minuten braucht bis ein Kollege es verstanden hat.



  • PhilippM schrieb:

    Auslösend war die Erkenntnis, dass es ein Anzeichen für schlechtes Design ist, wenn man länger als 15 Minuten braucht bis ein Kollege es verstanden hat.

    👍


Anmelden zum Antworten