Methodenaufruf in abgeleiteter Klasse erzwingen



  • Hallo allerseits,

    falls es zu diesem Thema schon was gibt, verweist mich doch bitte darauf.

    Ich habe versucht, in einer abstrakten Basisklasse im pure virtual DTor eine ebenso pure virtual Methode zu rufen, da abgeleitete Klassen diese ja implemetieren müssen!

    Nun hab ich hier im Forum aber gelernt, dass der DTor von abgeleiteten Klassen vor dem der Basisklasse abgearbeitet wird.

    Mein alter GCC 2.95.3 hat diese Konstellation problemlos geschluck und m.W. auch ausgeführt.
    Mein GCC 3.3 sagt hingegen:

    ApplicationC.cc: In destructor virtual ApplicationC::~ApplicationC()': ApplicationC.cc:5: error: abstract virtualvirtual void ApplicationC::close()'
    called from destructor

    Hier mal ein bisschen Code:

    Header:

    class ApplicationC
    {
     public:
            ApplicationC();
            virtual ~ApplicationC() = 0;
            virtual void init();
      virtual void close() = 0;
            virtual void processMessages(struct MsgPort *port) = 0; // hier noch unfein, da immer IntuiMessages genommen werden
    };
    

    Implementierung:

    ApplicationC::ApplicationC() { init(); }
    
    ApplicationC::~ApplicationC() { close(); }
    
    void ApplicationC::init() {}
    
    void ApplicationC::close() {}
    

    Warum hat der alte GCC nicht gemotzt?
    Und wie kann ich denn die Zielsetzung erreichen?

    Im Prinzip hätte ich gern, dass beim Beenden der Applikation automatisch die close-Methode gerufen wird!
    Geht das denn?

    Vielen Dank schon einmal!
    Ciao



  • ? Du kannst doch nicht als pur-virtual deklarieren und dann doch eine Definition reinhauen ...



  • na wenn du den desturktor pure virtual machst (darf man das überhaupt? kA), dann darfst du ihn doch nicht implementieren...

    Versuchs mal so:

    class app
    {
     public:
      virtual ~app() { close(); };
    
      virtual void close() = 0;
    };
    


  • Maxi schrieb:

    na wenn du den desturktor pure virtual machst (darf man das überhaupt? kA), dann darfst du ihn doch nicht implementieren...

    Soweit ich gelesen habe, darf man beides!
    Weiss nur nicht mehr, worin der Sinn in der Implementierung des pure virtual DTors bestand!

    Versuchs mal so:

    class app
    {
     public:
      virtual app() { close(); };
    
      virtual void close() = 0;
    };
    

    Hm, ich möchte die Methode aber nicht im Konstruktor aufrufen, da sie erst beim Löschen des Objektes aktiv werden soll!
    Zudem: Ein virtueller Konstruktor!? Da muss ich nochmal meine Bücher bemühen (oder ich versteh hier was komplett falsch! Bin noch C++-Neuling!)

    Ciao



  • Fuege dfen fehlenden ~ da hinzu dann passts wieder.

    Pure virtual heiszt soweit ich weisz soviel wie "wird nie aufgerufen" Das stimmt bei einem Destruktor wohl nur sehr selten (c\ich haette jetzt gesagt nie, aber wer weisz was da noch alles gibt, was ich nicht kenne)



  • Reth schrieb:

    Soweit ich gelesen habe, darf man beides!

    Korrekt. IMHO muss man sogar beides (oder anders: im Falle eines Dtors braucht auch die pure virtual Variante eine Implementierung), da am Destruktor Sachen wie vtable und so hängen, da bin ich mir aber nicht 100% sicher.


  • Mod

    Reth schrieb:

    Ich habe versucht, in einer abstrakten Basisklasse im pure virtual DTor eine ebenso pure virtual Methode zu rufen, da abgeleitete Klassen diese ja implemetieren müssen!

    Das resultiert in undefiniertem Verhalten. Da zum Zeitpunkt der Ausführung des Destruktors dynamischer Typ und statischer Typ übereinstimmen (das Objekt als Instanz der abgeleiteten Klasse existiert nicht mehr), kann ein dynamischer Aufruf einer virtuellen Methode nur die Implementierung in der Klasse des aufgerufenen Destruktors finden. Für rein-virtuelle Funktionen ist dies aber nicht erlaubt. Das ist logisch, wenn die Funktion dort gar nicht definiert ist; aber selbst wenn ein Funktionsrumpf existiert, darf dieser nicht so aufgerufen werden (ein qualifizierter Aufruf ist dagegen möglich).

    @Maxi: die Deklaration als rein virtuell bedeutet (abgesehen von obigem) nur zwei Dinge:
    1. Es können keine Objekte konstruiert werden, deren vollständiger Typ der dieser Klasse oder einer abgeleiteten Klasse, die diese Funktion nicht überschreibt, ist.
    2. Eine Definition der Funktion muss nur exististieren, wenn diese auch genutzt wird. Das ist beim Dtor immer der Fall, wenn ein Objekt einer abgeleiteten Klasse zerstört wird - deshalb muss hier stets eine Definition folgen (solange man nicht auf die Zerstörung des vollständigen Objekts verzichtet).

    An sich ist kein guter Grund einzusehen, der überhaupt das ursprüngliche Ziel rechtfertigen könnte. Überhaupt zu verlangen, dass eine close Funktion aufgerufen werden muss, kann ja nur in irgendwelchen Daten, die bereits in der Basisklasse existieren, zu suchen sein, dann müsste diese aber auch die notwendigen Schritte für die Zerstörung implementieren können. Ansonsten ist jede Ebene der Vererbungshierarchie selbst dafür Verantwortlich, hinter sich selbst aufzuräumen, ein Antizipieren dessen in der Basisklasse weder notwendig noch sinnvoll.



  • camper schrieb:

    An sich ist kein guter Grund einzusehen, der überhaupt das ursprüngliche Ziel rechtfertigen könnte. Überhaupt zu verlangen, dass eine close Funktion aufgerufen werden muss, kann ja nur in irgendwelchen Daten, die bereits in der Basisklasse existieren, zu suchen sein, dann müsste diese aber auch die notwendigen Schritte für die Zerstörung implementieren können. Ansonsten ist jede Ebene der Vererbungshierarchie selbst dafür Verantwortlich, hinter sich selbst aufzuräumen, ein Antizipieren dessen in der Basisklasse weder notwendig noch sinnvoll.

    Die Idee dahinter ist, dass der Implementierende der abstrakten Klasse sich drauf verlassen kann, dass close() immer gerufen wird und dort dann entsprechende Aktionen unterbringt (was natürlich auch im DTor möglich wäre, aber mir gefiel der Gedanke besser und vllt. gibt es ja ne Konstellation etwas aufräumen zu müssen, bevor der DTor gerufen wird).

    Aber wenn ich das recht verstanden habe, würde auch die Variante mit dem virtuellen DTor (nicht pure virtual) nicht funktionieren und zwar aus besagtem Grund der Aufrufreihenfolge der DToren!?

    Ciao



  • Wie camper schon sagte: Es macht keinen Sinn, wenn die (abstrakte) Basisklasse sich um die Aufräumarbeiten der abgeleiteten Klassen kümmern will.

    Du kannst natürlich selber eine close()-Methode definieren, die deine eigenen Daten wieder aufräumt. Und es ist kein Problem, diese Methode im Destruktor auch aufzurufen. Aber der Destruktor der abgeleiteten Klasse wurde bereits abgearbeitet, bevor der Basis-Dtor an die Reihe gekommen ist - also existieren deren Daten auch nicht mehr (und es macht wenig Sinn, wenn du dich darum kümmern willst, sie freizugeben).

    (genauso wird der Basis-Ctor durchlaufen, bevor die Daten (inklusive vtable) der abgeleiteten Klasse existieren und kann deshalb auch nur die eigene Version einer virtuellen Methode verwenden)



  • Mal ganz abgesehn davon, dass es eh ziemlich schlechter Stil ist, wenn jemand eine abgeleitete Klasse schreibt, dort Datenmember einbaut und mit ihnen rumfuhrwerkt, ohne hinterher wieder aufzuraeumen. Im grunde gilt "jeder kuemmert sich um seinen eigenen Sch**" und nicht "Eltern haften fuer ihre Kinder" 😉


Anmelden zum Antworten