[Abstrakte Klassen] Konstruktor und Destruktor Aufrufe



  • Hallo zusammen, kann mir bitte jemand folgende Situation erklären?

    class Abstact
    {
    public:
       ~Abstract();
       virtual void foo() = 0;
    };
    
    class Bar : public Abstract
    {
    public:
      virtual void foo() {}
    };
    
    void foobar(Abstract& obj) // <-- Hier: Warum funktioniert das?
    {
       obj.~Abstract(); // <-- Hier: Warum funktioniert das?
    }
    
    int main(void)
    {
      Bar a;
      foobar(a);
    }
    

    Wie funktionieren Referenzen auf Abstrakte Basisklassen? Eine Referenz bindet doch an ein Objekt, oder? Warum kann ich dann Referenzen auf Objekte machen, die es eigentlich nicht geben darf?

    Zerstört der Destruktor nur den teil der Basisklasse oder zerstört er das ganze Objekt? 😕 😕 😕

    Fragen über Fragen. Ich hoffe mir kann einer Erleuchtung verschaffen. 😉

    Edit:
    Compiler ist gcc 3.4 (cygwin unter Windows)

    Greets
    Tobi



  • Tobias Gerg schrieb:

    Wie funktionieren Referenzen auf Abstrakte Basisklassen? Eine Referenz bindet doch an ein Objekt, oder? Warum kann ich dann Referenzen auf Objekte machen, die es eigentlich nicht geben darf?

    Referenzen sind selbstdereferenzierende Zeiger. Es gibt halt einfach dann auch Basisklassenreferenzen.

    Zerstört der Destruktor nur den teil der Basisklasse oder zerstört er das ganze Objekt? 😕 😕 😕

    MACH SOWAS BITTE NIE! Destruktoraufrufe nur indirekt über delete! Sowas geht aber voll in die Hose, weil dein Objekt dann evtl. nimmer gültig ist (Z.B. Zeiger, die im Destruktor initialisiert wurden dann plötzlich gelöscht sind). Lass doch das Objekt hinter der Referenz sich selber zerstören.

    Und in deinem Beispiel wird nur der Basisteil zerstört, da der Destruktor in Abstract nicht virtuell ist.



  • Tobias Gerg schrieb:

    Wie funktionieren Referenzen auf Abstrakte Basisklassen? Eine Referenz bindet doch an ein Objekt, oder? Warum kann ich dann Referenzen auf Objekte machen, die es eigentlich nicht geben darf?

    Die Vererbung nennt man auch eine "Ist-ein"-Beziehung, und genau das ist es was hier benutzt wird: Es gibt kein Abstract als solches, aber es gibt Bar, und jedes Bar ist ein Abstract. In der Beziehung funktionieren Referenzen sehr änhlich wie Pointer, man kann eine Referenaz auf einen Basisklasse auch an Objekte aller abgeleiteten Klassen binden.

    Zerstört der Destruktor nur den teil der Basisklasse oder zerstört er das ganze Objekt? 😕 😕 😕

    Klares jein: Wenn du ein Objekt vom Typ Bar statisch erstellst, d.h. als normale Variable irgendwo im Code, dann wird es auch vollständig wieder zerstört. Der Compiler weiß dann ja, dass es ein Bar ist und ruft direkt dessen Destruktor auf (und darüber den Dtor von Abstract). Wenn du aber ein Bar über new erstellst, also dynamisch, dann sieht die Sache anders aus:

    Abstract* pa = new Bar;
    delete pa;
    

    Hier wird beim delete der Destructor des Abstract-Objekts aufgerufen, da der Dtor nicht virtuell ist. Der Rest des Objektes (also der Bar-Teil) wird nicht zerstört, das Verhalten ist undefiniert. Die Lösung dafür ist, den Dtor virtuell zu machen, dann wird beim delete über die vtable der richtige Dtor (der von Bar) gefunden und aufgerufen, so dass das ganze Objekt ordnungsgemäß zerstört wird.

    Es ist eigentlich ein MUSS, bei Klassen mit virtuellen Funktionen den Dtor auch virtuell zu machen, und es ist eine verbreitete Richtlinie, bei abstrakten Klassen auf jeden Fall schonmal den Dtor pur virtuell zu deklarieren. Definiert werden muss er allerdings trotzdem, da er durch die Dtoren der abgeleiteten Klassen immer aufgerufen wird.



  • Hallo ihr zwei,

    danke für die rasche Antwort. Mir war nicht klar, dass man an eine Refernz der Basis auch Objekte aller abgeleiteten Klassen binden kann.

    Das virtual beim Destruktur hab ich vergessen 🤡 , hab den Originalen Source gerade nicht zur Hand.

    Mit den Erklärungen wird es klarer... Danke 👍

    Gruß
    Tobi


Anmelden zum Antworten