Standard-Implementierung von "pure virtual" nicht vererbt?



  • Dadurch, dass du die Methode pure virtual machst, sagst du doch gerade, dass diese Methode in einer abgeleiteten Klasse implementiert werden muss!? Oder was dachtest du, mit der pure virtual Methode zu erreichen?



  • Es gibt bestimmt Umsteiger aus anderen Sprachen, die gelesen haben dass Interfaces in C++ durch Klassen mit pure virtual Methoden umgesetzt werden. Vielleicht weht daher der Wind, aber keine Garantie 😉



  • Also ich kenne keine andere Sprache, in der man Methoden eines Interface nicht implementieren muss. Was für einen Sinn hätte das?



  • Na ich meinte es jetzt schon so, dass in dem gegebenen Beispiel A ein interface sein soll. Darum alles pure virtual, weil eben Interface. Und dann soll die eine Methode halt auch noch eine Standard-Implementierung haben. Ist doch klar!



  • Ok, ich kenn aber keine Sprache, in der Methoden eines Interface eine Standardimplementierung haben können. Was für einen Sinn sollte das auch haben, Interfaces können doch normalerweise keine Datenmember haben!?
    C++ ist da wohl eher die Ausnahme, da man abstrakte Methoden in C++ tatsächlich implementieren kann. Das ändert dann aber nichts daran, dass die Klasse abstrakt ist und nicht instanziert werden kann...



  • Ich habe ja mit keinem Wort gesagt, dass der Gedankengang richtig wäre. Ich habe nur nachzuvollziehen versucht, weshalb jemand auf dem pure virtual beharren möchte, trotz der Tatsache, dass er eine Standardimplementierung geben möchte!



  • Schon klar, ich hab nur versucht, den Fehler in diesen Gedankengängen aufzuzeigen, für den Fall, dass einer davon tatsächlich der Grund für die Verwirrung wäre. 😉

    Abgesehen davon: Man kann in C++ sogar eine "Standardimplementierung" einer pure virtual Methode liefern. Nur muss man diese aus der abgeleiteten Klasse explizit aufrufen:

    class Base
    {
    public:
      virtual void blub() = 0
      {
        // ...
      }
    };
    
    class Derived : public Base
    {
    public:
      virtual void blub()
      {
        Base::blub();
      }
    };
    

    Denn so lange die rein virtuelle Methode nicht überschrieben wird, ist die Klasse abstrakt...



  • @dot

    class Base 
     { 
    public: 
       virtual void blub() = 0 
       { 
         // ... 
       } 
     };
    

    Die Schreibweise ist zwar naheliegend, aber ein Syntax-Error (warum auch immer).
    Bei virtual pure musst du die Methode ausserhalb der Klassendefinition definieren.



  • Da hast du natürlich absolut recht; da sieht man schön, wie oft man sowas braucht, dass ich nichtmal die korrekte Syntax zusammenbring...



  • Das wird aber in Effective C++ sogar explizit als Methode empfohlen, eine Standardimplementierung zur Verfügung zu stellen. Mit dem Vorzug, dass der Erbende noch mal drüber nachdenken muss, ob die Standardimplementierung wirklich dass ist, was gewollt wird.



  • Nun, ich verwend vollwertige Vererbung generell eher selten. Einzig mein GUI System mach heftigen Gebrauch von allen möglichen Formen von Vererbung (sogar virtual protected 😃 ) und dort will man nicht sämtliche Methoden immer und überall neu implementieren...



  • und was war die Situation, in der du virtual protected brauchtest?



  • Nunja, nehmen wir als Beispiel das Panel Control:

    class Panel : public virtual Control, protected virtual Parent
      {
        // ...
      };
    

    Panel implementiert das öffentliche Interface Control (Virtual Inheritance ist für Interfaces notwendig, damit z.B. die Methoden eines Interface teilweise in einer anderen Basisklasse implementiert sein können). Intern implementiert Panel auch das Interface Parent. Würde Panel allerdings virtual private von Parent ableiten, könnte nun niemand mehr von Panel ableiten, da bei Virtual Inheritance der Konstruktor der virtuellen Basisklasse in der most derived Class verfügbar sein muss. Daher virtual protected...

    Edit: Die Alternative wäre vermutlich, beim Ableiten von Panel immer auch nochmal private virtual von Parent abzuleiten...


  • Mod

    dot schrieb:

    Edit: Die Alternative wäre vermutlich, beim Ableiten von Panel immer auch nochmal private virtual von Parent abzuleiten...

    oder den Typ der Basisklasse auf andere Weise zu finden

    class Parent {};
    class Control {};
    class Panel : public virtual Control, private virtual Parent
    {};
    
    class MyPanel : public Panel
    {
       MyPanel() : Parent(), Panel()  {} // error
       MyPanel() : ::Parent(), Panel()  {} // ok
    };
    


  • Das geht? Interessant...Nachteil ist aber natürlich, dass der Code der abgeleiteten Klasse dadurch von der Basisklassenliste der Basisklasse abhängig wird, d.h. wenn irgendwo im Inheritance Graph eine neue virtual Base dazukommt, muss ich den Code aller Blätter anpassen!?


  • Mod

    dot schrieb:

    Das geht? Interessant...Nachteil ist aber natürlich, dass der Code der abgeleiteten Klasse dadurch von der Basisklassenliste der Basisklasse abhängig wird...

    Das ist er doch sowieso schon?

    Schöner wäre wahrscheinlich

    class MyPanel : public Panel
     {
       typedef ::Parent Parent;
       MyPanel() : Parent(), Panel()  {}
     };
    


  • Nicht unbedingt:

    class Parent {}; 
    class Control {}; 
    class Panel : public virtual Control, protected virtual Parent 
    {}; 
    
    class MyPanel : public Panel 
    { 
       MyPanel() {} // ok
    };
    

  • Mod

    dot schrieb:

    Nicht unbedingt:

    class Parent {}; 
    class Control {}; 
    class Panel : public virtual Control, protected virtual Parent 
    {}; 
    
    class MyPanel : public Panel 
    { 
       MyPanel() {} // ok
    };
    

    Das wäre allerdings auch mit private-Vererbung ok.



  • Oha, stimmt, dann muss ich wohl einen anderen Grund für das protected gehabt haben, den ich nun leider vergessen hab... 🤡

    Edit: Der Grund war wohl, dass abgeleitete Klassen sonst keine Methoden des Interface überschreiben können...

    Edit 2: Wobei die natürlich auch einfach nochmal von Parent erben könnten...


  • Mod

    dot schrieb:

    Edit: Der Grund war wohl, dass abgeleitete Klassen sonst keine Methoden des Interface überschreiben können...

    Das ist auch nicht der Fall 😉


Anmelden zum Antworten