rein virtulle Destruktoren



  • Nicht-virtuelle Funktionen können nicht abstrakt sein. Vielleicht hast du das virtual vergessen.

    Da abgeleitetete Klassen nicht definiert sind, versucht er A:Init() aufzurufen.

    Es ist vollkommen egal, was in den abgeleiteten Klassen ist, er ruft in jedem Fall A::Init auf. Deswegen macht es auch keinen Sinn, diese Funktion virtual zu machen.



  • Wenn du in einem Konstruktor eine virtuelle Methode aufrufst, wird nicht die Überladung aufgerufen, die das endgültige Objekt haben wird, sondern die, die zu der Klasse gehört, in deren Konstruktor du dich gerade befindest. In deinem Beispiel (auch wenn Init virtual deklariert wäre, was vtml. deine Absicht war) würde der Compiler gar nicht erst versuchen, die Methode der Kindklasse aufzulösen sondern gleich A::Init zu benutzen versuchen.

    Das liegt daran, dass *this zu diesem Zeitpunkt noch kein Objekt der Kindklasse ist. Eventuell durch abgelittene Klassen neu hinzugekommene Objektteile sind zu diesem Zeitpunkt noch nicht konstruiert, und eine virtuelle Methode muss sich darauf verlassen können, mit einem vollständigen Objekt seiner Klasse umzugehen.



  • Ich hab mich nur unglaublich schlecht ausgedrückt. Meinte eigentlich genau das, was ihr sagt. ^^



  • Ich bin jetzt etwas verwirrt 😞

    Wie kann man eine rein virtuelle Funktion aufrufen (abgesehen vom Destruktor), auch wenn man sie außerhalb der Klasse definiert ?

    Angenommen man hat so etwas wie:

    class A
    {
      public:
        virtual void foo() = 0;
      /* ... */
    };
    
    void A::foo()
    {
      /* DO SOMETHING */
    }
    

    Obwohl A::foo() jetzt definiert ist, kann man es doch nicht schaffen irgendwie das "DO SOMETHING" auszuführen oder?

    Gruß 🙂



  • MatheStein schrieb:

    Wie kann man eine rein virtuelle Funktion aufrufen

    Genauso wie nicht rein virtuelle Funktionen.



  • Hast du vllt ein Beispiel?

    In der abstrakten Klasse selbst geht glaube ich nicht, da man diese nicht instanziieren kann und in Unterklassen geht es denke ich nicht, da dort das foo wegen dem "=0" überschrieben sein muss und wegen "virtual" die Implementation aus der Unterklasse genommen wird. So sehe ich das zumindest bis jetzt ^^

    Gruß 🙂



  • MatheStein schrieb:

    Hast du vllt ein Beispiel?

    OK, deine Überlegungen sind richtig, über den normalen virtuellen Mechanismus kriegt man sie nicht zu fassen. Man kann diesen aber umgehen, indem man die Klasse dazu angibt:

    A::foo();
    

    Oder halt im Konstruktor, wie schon erwähnt.



  • Übliche Beispiel ist das Aufrufen aus der abgeleiteten Methode:

    class B : public A
    {
      public:
        virtual void foo();
    };
    
    void B::foo()
    {
      A::foo();
    }
    

    Aber du kannst auch jederzeit dann das A::foo() aufrufen, z.B.:

    B b;
    
    b.A::foo();
    

    Ausführliches Beispiel unter http://ideone.com/1T0Yj



  • Besten Dank Leute, jetzt habe ich es verstanden 🙂

    Eine abschließende Frage noch. Kann man so etwas irgendwie elegant verkürzen:

    class A
    {
      public:
        virtual ~A() = 0;
    
    };
    
    ~A() {}
    

    Ich meine mal so etwas ähnliches wie

    virtual ~A() {} = 0;
    

    gesehe zu haben, aber das kompiliert bei mir nicht.

    BTW:
    Das man den Destruktor an dieser Stelle explizit definieren muss liegt daran, dass man ihn deklariert hat durch

    virtual ~A() = 0;
    

    und somit kein Standard-Destruktor mehr vom Compiler zur Verfügung gestellt wird oder?

    Gruß 🙂



  • seldon schrieb:

    Wenn du in einem Konstruktor eine virtuelle Methode aufrufst, wird nicht die Überladung aufgerufen, die das endgültige Objekt haben wird, sondern die, die zu der Klasse gehört, in deren Konstruktor du dich gerade befindest

    Das aufrufen einer virtuellen Methode im Konstruktor ist undefiniert. Was tatsaechlich passiert ist kompilerabhaengig. Einfache Regel: Keine virtuellen Methoden im Konstruktor aufrufen.



  • knivil schrieb:

    Das aufrufen einer virtuellen Methode im Konstruktor ist undefiniert. Was tatsaechlich passiert ist kompilerabhaengig. Einfache Regel: Keine virtuellen Methoden im Konstruktor aufrufen.

    Kompletter Bullshit.



  • Bashar schrieb:

    knivil schrieb:

    Das aufrufen einer virtuellen Methode im Konstruktor ist undefiniert. Was tatsaechlich passiert ist kompilerabhaengig. Einfache Regel: Keine virtuellen Methoden im Konstruktor aufrufen.

    Kompletter Bullshit.

    Genau.

    Es wird immer die Variante aufgerufen, die zum "aktuellen" Objekttyp gehört.
    Ab dem Zeitpunkt wo Konstruktor A::A anfängt "eigenen" Code auszuführen, ist das Type "A".

    Auch wenn es eine Klasse B gibt, die von A abgeleitet ist, und man ein Objekt vom Typ "B" erzeugt.

    So lange Konstruktor B::B nicht fertig ist mit dem Aufrufen der Konstruktoren der Basisklassenobjekte, und angefangen hat "eigenen" Code auszuführen, ist das B nämlich noch kein B, sondern ein A.

    MatheStein schrieb:

    Ich meine mal so etwas ähnliches wie

    virtual ~A() {} = 0;
    

    gesehe zu haben, aber das kompiliert bei mir nicht.

    Vertausch mal das "= 0" mit dem "{}".



  • knivil schrieb:

    MatheStein schrieb:

    Ich meine mal so etwas ähnliches wie

    virtual ~A() {} = 0;
    

    gesehe zu haben, aber das kompiliert bei mir nicht.

    Vertausch mal das "= 0" mit dem "{}".

    Klappt leider auch nicht 😞



  • Die Sprachgrammatik lässt das schlicht und einfach nicht zu.



  • Ich versteh da auch den Sinn gar nicht. Eine pure-virtual-Funktion sorgt dafür, dass Instanzen dieser Klasse nicht möglich sind, und vor allem, dass in abgeleiteten Klassen diese Funktion implementiert werden muss (oder als pure-virtual weitergereicht). Welchen Sinn macht es jetzt, in einer Basisklasse festzulegen, dass abgeleitete Klassen den Destruktor implementieren müssen? Und wenn es nur um die Instanziierung geht, warum nicht eine normale pure-virtual-Funktion nehmen? Wenn das keinen Sinn macht, was ist der Hintergrund, warum du Instanzen verbieten willst?



  • Bashar schrieb:

    Kompletter Bullshit.

    Na ich hab es nicht so mit dem Standard, aber vielleicht kannst du ja die entsprechende Stelle posten.

    Edit: Ok. hab es nachgelesen. Nein, nicht im Standard.



  • arghonaut schrieb:

    Ich versteh da auch den Sinn gar nicht. Eine pure-virtual-Funktion sorgt dafür, dass Instanzen dieser Klasse nicht möglich sind, und vor allem, dass in abgeleiteten Klassen diese Funktion implementiert werden muss (oder als pure-virtual weitergereicht). Welchen Sinn macht es jetzt, in einer Basisklasse festzulegen, dass abgeleitete Klassen den Destruktor implementieren müssen? Und wenn es nur um die Instanziierung geht, warum nicht eine normale pure-virtual-Funktion nehmen? Wenn das keinen Sinn macht, was ist der Hintergrund, warum du Instanzen verbieten willst?

    @arghonaut: Angenommen du willst eine Basisklasse ohne Methoden als Basis fuer eine Vererbungshierarchie (Sinnhaftigkeit hinten angestellt). Jetzt sollen alle abgeleiteten Klassen einen eigenen Destruktor implementieren. Mit pure virtual wird das erzwungen. Wenn ein Objekt zerstoert wird, werden nun alle Basisklassendestruktoren in entsprechender Reihenfolge aufgerufen, auch der Wurzelklasse fuer den Ableitungsbaum. Besitzt diese Klasse keine Implementation des Destruktors kommt es zu einem Laufzeitfehler.



  • Hast du ein Beispiel parat, in dem es essentiell ist, dass ein eigener Destruktor implementiert wird? Wenn halt selber nichts zu zerstören ist - also der vom Compiler generierte Destruktor vollkommen ausreicht - welchen Sinn macht es, diesen dann trotzdem implementieren zu müssen? Es würde doch deutlich mehr Sinn machen, in Base einen leeren virtuellen Destruktor anzubieten.



  • Der Laufzeitfehler heißt dann "pure virtual function call(ed)". Eine Erklärung dafür gibt es bei http://www.artima.com/cppsource/pure_virtual.html



  • arghonaut schrieb:

    Hast du ein Beispiel parat, in dem es essentiell ist ...

    Nichts ist essenziell. NUr essen, trinken, sterben. Dumme Frage! Auch habe ich die Sinnhaftigkeit hinten angestellt. ... Ich korrigiere mich. Ziel ist es nicht, die Implementation des Destruktors zu erzwingen, sonder die Basisklasse abstrakt zu machen. Wenn die Basiskalsse abstrakt sein soll, ohne weitere Funktionalitaet, dann ist das ein Weg.


Anmelden zum Antworten