geerbte virtuelle Methoden bei Mehrfachvererbung



  • Hi!

    Wie werden eigentlich (rein) virtuelle Methoden bei MV aufgelöst?

    Ich habe ein pure virtual interface

    class Interface {
    virtual void foo() = 0;
    virtual void bar() = 0;
    };
    

    Eine Basisklasse

    class Base {
    virtual void foo() { cout << "foo"; }
    };
    

    und eine abgeleitete Klasse, die das Interface implementiert

    class Derived: public Base, public Interface {
    virtual void bar() { cout << "bar"; }
    };
    

    Ich hatte eigentlich erwatet, dass ich in Instancen von Derived jetzt die Methode foo aus Base geerbt habe.
    Stattdessen sagt mir der Compiler (gcc): "cannot allocate an object of abstract type 'Derived' because the following virtual functions are pure within 'Derived': virtual void Interface::foo()

    Muss das so sein? Bleibt mir nichts anderes übrig, als in Derived eine Methode

    virtual void foo() {Base::foo();}
    

    oder

    virtual void foo() {this->foo();}
    

    zu machen?

    Gruß
    Phil



  • Ja, dir bleibt nichts anderes übrig. Base::Foo() hat nichts mit Interface::Foo() am Hut, daher kann der Compiler die VMT nicht richtig auflösen, da nur das reine Derived::bar() definiert ist, aber kein Derived::foo(), sondern eben nur Base::Foo().



  • PhilippM schrieb:

    Muss das so sein? Bleibt mir nichts anderes übrig, als in Derived eine Methode

    virtual void foo() {Base::foo();}
    

    oder

    virtual void foo() {this->foo();}
    

    zu machen?

    Solange du nicht die Sprache wechseln willst, bleibt dir nichts anderes. (Und Variante 2 endet übrigens recht schnell mit einem Stack-Überlauf.)

    In deinem Beispiel wäre es sinnvoller, Base auch schon Interface implementieren zu lassen, aber vermutlich hättest du nicht Mehrfachvererbung gewählt, wenn das eine Option wäre. Möglicherweise kannst du aus Base einen Mixin-Typen machen:

    template <class I>
        class Base : public I
    { ... };
    
    class Derived : public Base <Interface>
    { ... };
    

    Das grundsätzliche Problem wird dadurch allerdings nicht behoben: in C++ ist es nur mit Verrenkungen möglich, ein Interface teilweise oder implizit zu implementieren. Das ist einer der Gründe, weshalb COM-Programmierung mit C++ suckt 😞

    Delphi löst das z.B. eleganter; dort kann man Teile eines Interfaces an Klassen delegieren, die das Interface gar nicht kennen:

    type
      IIntf = interface
        procedure Foo;
        procedure Bar;
      end;
    
      TBase = class (TAggregatedObject)
        procedure Foo;
      end;
    
      TDerived = class (TInterfacedObject, IIntf)
      private
        FFooImpl: TBase;
      public
        property FooImpl: TBase read FFooImpl implements IIntf;
        procedure Bar;
        constructor Create;
      end;
    

    Edit: Fehler in Mixin-Beispiel beseitigt.



  • audacia schrieb:

    Solange du nicht die Sprache wechseln willst, bleibt dir nichts anderes. (Und Variante 2 endet übrigens recht schnell mit einem Stack-Überlauf.)

    Uups, in der Tat ist 2 blödsinn.

    Das erste funktioniert, ist aber reichlich umständlich. Geht da nicht eine "using" Deklaration??



  • Kann man nichts mit virtual inheritance machen?



  • PhilippM schrieb:

    Geht da nicht eine "using" Deklaration??

    Nein.

    knivil schrieb:

    Kann man nichts mit virtual inheritance machen?

    Virtuelle Vererbung bedeutet, daß gemeinsame Vorfahren mehrerer Basisklassen nur eine Repräsentation im Objekt haben. Das Problem hier tangiert sie nicht.


  • Administrator

    PhilippM schrieb:

    Geht da nicht eine "using" Deklaration??

    Nicht das ich wüsste. Ein using würde die Methode nur raufholen und quasi eine Überladung ermöglichen. Die Klasse würde aber abstrakt bleiben. Die Methoden haben halt, wie schon Ad aCTa gesagt hat, nichts gemeinsam. Es sind zwei völlig unterschiedliche Methoden.
    Erst durch eine virtuelle Methode in einer Klasse unterhalb, kann man die beiden Methoden verbinden. Oder man lässt halt Base von Interface erben und erbt in Derived nur noch von Base.

    knivil schrieb:

    Kann man nichts mit virtual inheritance machen?

    Ziemlich unwahrscheinlich, da virtual inheritance dazu verwendet wird, dass man keine doppelten Basisklassen hat. Es sind hier aber zwei unterschiedliche Klassen, von welchen geerbt werden, daher sind es auch klar zwei unterschiedliche Methoden.

    Edit: Mist, zu spät...

    Grüssli


Anmelden zum Antworten