Methodenaufruf bei Mehrfachvererbung



  • Moin,

    ich benutze in meinem Projekt Mehrfachvererbung (ich weiß, ich weiß, ist eben manchmal gefährlich ;-).

    Ich benutze eine Klasse CEnabled, in der festgehalten wird, ob ein Objekt aktiviert ist ober nicht. Relevant ist nur der Konstruktor.

    class CEnabled:CEnabled(bool bEnabled = false)
    {
    m_bEnabled = bEnabled;
    }

    // Folgender Konstrukt bzgl. abgeleiteter Klassen sei jetzt gegeben:

    class CBase1::CBase(void): public CEnabled
    {
    ...
    }

    class CBase2::CBase(void): public CEnabled
    {
    ...
    }

    class CDerived::CDerived(void): public CBase1, public CBase2, public CEnabled
    {
    ...
    }

    // So weit, so gut: Bei CDerived sind beide Basisklassen CBase1 und CBase2 von CEnabled abgeleitet. Aber auch CDerived selbst ist von CEnabled abgeleitet (da auch diese Klasse eine eigene Aktivierungsinfo benötigt).

    // Jetzt versuche ich bei der Konstruktordefinition von CDerived die Basisklassen CEnabled
    // der beiden Basisklassen CBase1 und CBase2 zu initialisieren:

    CDerived::CDerived(void): CBase1::CEnabled(false), CBase2::CEnabled(true)
    {
    ...
    }

    // Das funktioniert wie erwartet ... und jetzt versuche ich alternativ nur die Basisklasse CEnabled direkt bei CDerived zu initialisieren:

    CDerived::CDerived(void): CEnabled::CEnabled(false)

    Das funktioniert nicht: error C2387: "CEnabled": Mehrdeutige Basisklasse.

    Auch

    CDerived::CDerived(void): CDerived::CEnabled::CEnabled(false)

    funktoiniert nicht.

    Wieso? Bzw. wie muss die Initialisierung aussehen?

    Gruß Frank



  • Hast du denn mal

    CDerived::CDerived() // <- kein "void"
     : CDerived::CEnabled(false) // bzw. nur CEnabled(false)
    

    ausprobiert?

    Aber willst du wirklich mehrfach die Basisklasse CEnabled in deinen abgeleiteten Klassen (bzw. Objekten) haben? Wäre hier nicht virtuelle Vererbung sinnvoller? Denn je nachdem wie du das Objekt ansprichst, d.h. über welche Basisklasse, hätte es bei dir unterschiedliche CEnabled-Zustände.

    PS: Verwende Code-Tags hier im Forum.



  • Danke für deine Antwort.

    > Hast du denn mal ausprobiert

    Ja, habe ich!

    CDerived::CDerived(): CDerived::CEnabled(false)
    

    funktioniert auch nicht (kommt die gleiche Fehlermeldung), deshalb ja die Frage hier im Forum.

    > hätte es bei dir unterschiedliche CEnabled-Zustände.

    Ja, genau das ist ja die Intention!

    Hat wer anders noch einen Tipp?



  • Wie sehen denn die Konstruktoren von CBase1 und 2 aus?
    Das ist doch sowieso sinnvoll, dass die auch einen bool-ctor kriegen und dann den
    CEnabled(bool) ctor aufrufen.

    Dann geht das ja ganz normal mit

    CDerived()
    	: CBase1(true), CBase2(), CEnabled(false) // zB
    {
    }
    


  • Welchen Compiler verwendest du?
    Denn schon

    CDerived::CDerived(void): CBase1::CEnabled(false), CBase2::CEnabled(true)
    

    sollte eine Fehlermeldung ergeben, da man nur direkte Basisklassen initialisieren kann!
    Du müßtest also für CBase1 und CBase2 die Konstruktoren entsprechend erzeugen, welche CEnabled dann initialisieren (oder alternativ den Parameter weiterleiten).

    Unter Ideone-Code habe ich mal ein funktionierendes Beispiel dafür erzeugt.
    Einzig der Zugriff auf derived.IsEnabled() erzeugt die Fehlermeldung

    error: ‘CEnabled’ is an ambiguous base of ‘CDerived’

    Evtl. kennen Camper oder SeppJ hier die korrekte Lösung zur Auslösung der Mehrdeutigkeit.
    Weder

    derived.CEnabled::IsEnabled()
    

    noch

    derived.CDerived::CEnabled::IsEnabled()
    

    nimmt der gcc.



  • "Ist" den ein CDerived bei dir ein CEnabled, d.h. ergibt die Vererbung überhaupt logisch einen Sinn oder willst du nicht vielleicht lieber ein Objekt vom Typ CEnabled in deiner Klasse anlegen?

    Ansonsten gibt der Code auch schon die Warnung:
    (also ich habs mal simplifiziert:

    struct Enabled {
        bool enabled;
        Enabled(bool enabled) : enabled(enabled) {}
    };
    struct B : public Enabled {};
    struct D : public Enabled, public B {};
    
    int main() {
    }
    
    $ clang++-5.0 -Wall -Wextra mfv.cpp
    mfv.cpp:6:12: warning: direct base 'Enabled' is inaccessible due to ambiguity:
        struct D -> struct Enabled
        struct D -> struct B -> struct Enabled [-Winaccessible-base]
    struct D : public Enabled, public B {};
               ^~~~~~~~~~~~~~
    

    Die Frage ist also eher, was du eigentlich erreichen willst. Dieses Konstrukt erscheint mir nicht sinnvoll.



  • Ich ziehe meine Anfrage zurück, Ursache ist gefunden.

    Bei der Deklaration der Basisklassen hatte ich wohl einen Ctrl-C-Tatter:

    Statt

    CDerived::CDerived(void): public CBase1, public CBase2
    

    stand da:

    CDerived::CDerived(void): public CBase1, public CBase1, public CBase2
    

    ... also zweimal CBase1 als Basisklasse 😡 ... Dadurch war wohl jede Angabe einer Initialisierung bei der Definition des Konstruktors mehrdeutig. Sorry ... und danke für eure Bemühungen!



  • Wie hast du denn das von Th69 angesprochene Problem gelöst?
    Also wie greifst du auf den CDerived::CEnabled-Teil zu?


Log in to reply