linker-Fehler bei abstraktem virtuellen Dtor



  • Ja meinte ich. Danke.



  • Also nochmal:

    Wenn ich

    virtual ~Foo() = 0;
    

    schreibe, dann krieg ich den Linker-Fehler (bei VC 7.1, nicht bei BCB 5.5).
    Wenn ich Euch jetzt richtig versteht müsste das aber funzen?

    Den Linker-Fehler krieg ich nicht mehr, wenn ich

    virtual ~Foo(){};
    

    oder

    virtual ~Foo()=0{};
    

    schreibe, wobei zweiteres komisch aussieht und, wenn ich Euch richtig verstehe eigentlich falsche syntax ist (aber von VC7.1 und BCB 5.5, problemlos gefressen wird) - aber egal. Was micht interessiert ist der pure virtual dtor.



  • Mein BCB5 wirft bei deiner ersten Variante einen Linkerfehler und bei der dritten einen Compilerfehler (geht also beides nicht). Bei der zweiten Variante ist die Klasse nicht abstrakt (es sei denn es ist noch eine abstrakte Funktion drin).
    Also normalerweise

    virtual ~Foo()=0;
    

    und dann später

    Foo::~Foo() {}
    

    Siehe auch "Effektiv C++ programmieren" Lektion 14.



  • kartoffelsack schrieb:

    Den Linker-Fehler krieg ich nicht mehr, wenn ich

    virtual ~Foo(){};
    

    oder

    virtual ~Foo()=0{};
    

    schreibe, wobei zweiteres komisch aussieht und, wenn ich Euch richtig verstehe eigentlich falsche syntax ist (aber von VC7.1 und BCB 5.5, problemlos gefressen wird) - aber egal. Was micht interessiert ist der pure virtual dtor.

    Shade Of Mine schrieb:

    kartoffelsack schrieb:

    funzen tuts, wenn ich
    virtual ~Foo()=0{};
    schreibe.

    Nein, das ist verboten. entweder körper oder =0, beides geht nicht.
    aber ein

    virtual ~Foo() =0;

    Foo::~Foo() {}
    wäre korrekt.

    was ist unklar?



  • was ist unklar?

    Mit Braunsteins aussage ist mir jetzt gleich garnixmehr klar 😉

    Also normalerweise

    virtual ~Foo()=0;
    

    und dann später

    Foo::~Foo() {}
    

    Das heißt also, wenn ich
    ~Foo()=0;
    schreibe, muss ich den Dtor trotzdem implementieren?



  • Ja.
    Das hat Shade aber auch schon gesagt.



  • ok, jetzt hab ich's kapiert. Und außerdem hab ichs kapiert, dass ihr das schon gesagt habt 😉

    Danke! 🙂



  • Hallo,
    das ist imo so ein Problem, dass nur deshalb existiert, weil es so unendlich viele schlechte C++ Einsteigerbücher gibt, in denen selbsternannte Experten entweder krampfhaft versuchen ein Thema zu vereinfachen oder aber selbst schlicht und einfach keine Ahnung haben.

    Beispiel zum Thema:
    Schildt schreibt in seinem grausiligen "C++ Entpackt":

    Eine rein virtuelle Funktion ist eine virtuelle Funktion, die in der Basisklasse keine Definition besitzt.

    Klasse. Kurz, knapp und KÄSE!
    Aber "C++ Entpackt" ist nicht das einzige Buch in dem die Eigenschaft rein-virtuell fälschlicherweise so definiert wird.
    Einige versuchen später noch mit Gewalt die "Ausnahme rein virtuelle Dtor" unterzubringen, aber da haben die meisten bereits den falschen (und kürzeren) Merksatz abgespeichert. Da ist es doch kein Wunder, dass am Ende hauptsächlich eins übrig bleibt: Verwirrung.

    Imo ist das ein typisches Beispiel für eine Situation wo man ein komplexes Feature lieber etwas umfangreicher und dafür korrekt (muss ja nicht vollständig sein) als einfach und falsch einführen sollte.



  • Wieder was gelernt. Die Verwirrung hat mich zwischenzeitlich auch schon erwischt.

    Aber: warum ist das eigentlich so gelöst worden? Wenn ich eine rein virtuelle Funktion mache, dann will ich in der Regel erzwingen, das jemand, der von meiner Klasse ableitet, gezwungen wird, diese Funktion zu implementieren. Wenn ich aber jetzt mal das obige Beispiel mit dem virtuellen Dtor meinem VC7.1 vorsetze, so meckert er nicht, wenn ich von der abstrakten Basisklasse ableite und keinen eigenen Dtor schreibe.

    Warum das dann also?



  • Shade Of Mine schrieb:

    Nein, das ist verboten. entweder körper oder =0, beides geht nicht.

    Sicher?

    #include <iostream>
    
    class Foo
    {
    public:
      virtual void whatever() = 0;
    };
    
    class Bar : public Foo
    {
    public:
      virtual void whatever();
    };
    
    void Foo::whatever()
    {
      std::cout << "world!\n";
    }
    
    void Bar::whatever()
    {
      std::cout << "hello\n";
      Foo::whatever();
    }
    
    int main()
    {
      Bar test;
      test.whatever();
    }
    


  • finix schrieb:

    Sicher?

    Ja.

    Mir kommt es so vor, als würden meine Beiträge hier nicht genau gelesen werden.

    virtual void foo() = 0 {}
    geht nicht.

    aber

    virtual void foo() = 0;

    void Foo::foo() {}

    geht schon.



  • Shade Of Mine schrieb:

    Mir kommt es so vor, als würden meine Beiträge hier nicht genau gelesen werden.

    Ganz genau. 🙄 Sorry, sah auf die schnelle so aus als wäre der Code nur zur Unterstreichung der Aussage "entweder körper oder =0" gemeint.



  • class foo {
    public:
      virtual ~foo()=0;
      virtual void x()=0;
    };
    
    foo::~foo() {}
    // wenn foo::~foo() nicht implementiert ist => link-fehler
    // macht für mich sinn da automatisch von abgeleiteten klassen aufgerufen
    
    void foo::x() {}
    // pure virtual aber trotzdem implementiert ( das war neu für mich )
    
    class bar :public foo {
    public:
      //virtual  ~bar(){}
      // muss nicht implementiert werden obwohl foo::~foo() als pure virtual deklariert ???
      // andererseits macht es auch keinen sinn die implementation eines dtor's zu erzwingen.
      // welchen sinn macht dann die decl virtual ~foo()=0; ????
      // oder ist das ein bug in meinem compiler (g++)
    
      virtual void x();
    };
    
    void bar::x() { 
      // das macht sinn ich bin gezwungen die methode bar::x() zu implementieren,
      // kann aber die implementation von foo::x() verwenden
      foo::x(); 
    }
    
    int main() {
       bar t;
    }
    


  • finix schrieb:

    #include <iostream>
    
    class Foo
    {
    public:
      virtual void whatever() = 0;
    };
    
    class Bar : public Foo
    {
    public:
      virtual void whatever();
    };
    
    void Foo::whatever()
    {
      std::cout << "world!\n";
    }
    
    void Bar::whatever()
    {
      std::cout << "hello\n";
      Foo::whatever();
    }
    
    int main()
    {
      Bar test;
      test.whatever();
    }
    

    aber was soll das bringen? das widerspricht ja dem "konzept" von solchen funktionen (func() = 0;) -> sollen eigentlich eine einheitliche schnittstelle darstellen; die eigentlichen implementationen sollen die abgeleiteten klassen "übernehmen" 😕 😕 😕



  • Lars Hupel schrieb:

    aber was soll das bringen? das widerspricht ja dem "konzept" von solchen funktionen (func() = 0;) -> sollen eigentlich eine einheitliche schnittstelle darstellen; die eigentlichen implementationen sollen die abgeleiteten klassen "übernehmen" 😕 😕 😕

    Nein, es widerspricht nicht.

    Denn =0 heisst: abgeleitete Klasse muss es implementieren.

    nun kann in Base aber dennoch sinnvolle 'hilfs funktionalität' implementiert sein. zB am beispiel von Java -> die clone Methode.

    In C++ könnte man das mit einer rein virtuellen Methode clone() machen. Die abgeleitete Klasse muss clone() definieren aber dennoch Base::clone() aufrufen, weil ja auch Base geklont werden will. So hat man dann in Object eine rein virtuelle clone Methode mit einem Körper.

    Da widerspricht sich nichts.



  • Ich frag mich was die jetzige Diskussion soll. AFAIK benötigt nur ein rein virtueller Destruktor einen Körper. Andere rein virtuelle Funktionen nicht, obwohl es natürlich nicht verboten ist einen zu erzeugen.
    Ein rein virtueller Destruktor ist auch nur dann nötig, wenn man die Klasse abstrakt machen will und keine anderen Funktionen zur Verfügung stehen.



  • Braunstein schrieb:

    Ich frag mich was die jetzige Diskussion soll. AFAIK benötigt nur ein rein virtueller Destruktor einen Körper. Andere rein virtuelle Funktionen nicht, obwohl es natürlich nicht verboten ist einen zu erzeugen.
    Ein rein virtueller Destruktor ist auch nur dann nötig, wenn man die Klasse abstrakt machen will und keine anderen Funktionen zur Verfügung stehen.

    wenn das wirklich so wäre würde das ganze für mich sinn machen, aber zumindest bei g++ bin ich nicht gezwungen einen rein virtuellen dtor in abgeleiteten klassen zu implementieren, also wird die klasse auch nicht rein abstrakt. ( siehe mein voriges posting )
    Kurt.



  • Du vergisst, das in deinem Fall der Compiler automatisch einen default Destruktor in der abgeleiteten Klasse erstellt.



  • @Braunstein

    genau, also was habe ich dann von einem pure virtual Dtor? Es wird automatisch in der abgeleiteten Klasse ein Dtor erstellt (muß ja auch). Ich sehe da im Moment keinen Unterschied zum virtuellen Dtor 😕 .



  • TheBigW schrieb:

    @Braunstein

    genau, also was habe ich dann von einem pure virtual Dtor? Es wird automatisch in der abgeleiteten Klasse ein Dtor erstellt (muß ja auch). Ich sehe da im Moment keinen Unterschied zum virtuellen Dtor 😕 .

    Der Sinn wurde bereits erklärt. Ein rein virtueller Destruktor ist dann sinnvoll, wenn du eine abstrakte Klasse erzeugen willst, du aber keine andere rein virtuelle Funktion hast. Z.B. weil alle deine virtuellen Funktionen eine sinnvolle Default-Implementierung haben und diese auch per später Bindung aufrufbar sein sollen.


Anmelden zum Antworten