Kein virtuell in dem Konstrukteur



  • Hallo,

    Man sagt ja immer man solle keine virtuelle Funktion in dem Konstrukteur aufrufen, aber wie ist dies gemeint? Im Internet finde ich immer folgendes Beispiel:

    class Transaction {
    public: 
        Transaction();
        virtual void logTransaction() const = 0;
    };
    
    Transaction::Transaction()
    {
        logTransaction();
    }
    
    class BuyTransaction: public Transaction {
    public:
        virtual void logTransaction() const {}
    };
    
    class SellTransaction: public Transaction {
    public:
        virtual void logTransaction() const;
    };
    

    Aber jenes kompiliert bei mir nicht, da der Linker sagt, er könne das Symbol logTransaction@Transaction nicht finden.

    Und wenn ich in der abgeleiteten Klasse eine virtuelle Methode aufrufe, die diese abgeleitete Klasse implementiert, ist dies doch erlaubt oder? 😕



  • Wenn Du im Konstruktor der Basis Klasse eine virtuelle Funktion (ebendieser Basisklasse) aufrufst ist der abgeleitete Teil der Klasse noch nicht konstruiert. Es findet also kein Dispatching auf die richtige Funktion statt.

    Im Falle von rein virtuellen Funktionen (wie bei Dir) kann das schon der Linker erkennen. Im Fall von (nicht rein) virtuellen Funktionen wird einfach die Funktion der Basis Klasse aufgerufen. Nicht das was Du vermutlich möchtest.

    Simon



  • C++. schrieb:

    Man sagt ja immer man solle keine virtuelle Funktion in dem Konstrukteur aufrufen, aber wie ist dies gemeint? Im Internet finde ich immer folgendes Beispiel:...

    Aber jenes kompiliert bei mir nicht, da der Linker sagt, er könne das Symbol logTransaction@Transaction nicht finden.

    Logisch, da in der Klasse Transaction keine konkrete Implementierung existiert. Würde die Methode logTransaction() nur virtuell mit Implementierung, nicht aber pure virtuell deklariert werden, würde die Definition gefunden werden.

    C++. schrieb:

    Und wenn ich in der abgeleiteten Klasse eine virtuelle Methode aufrufe, die diese abgeleitete Klasse implementiert, ist dies doch erlaubt oder? 😕

    Wenn du in dem Konstruktor einer Klasse A eine implementierte Funktion dieser Klasse aufrufst, ist dies auch erlaubt. ABER: Was ist wenn du von dieser Klasse A eine Klasse B ableitest und eben diese (virtuelle) Funktion überschreibst? Ist es für den Benutzer B wirklich intuitiv wenn der Konstruktor des A-Anteil die A-Variante der Funktion aufruft, obwohl sie virtuell ist und in B Überschrieben wurde?

    Wenig intuitiv und imho auch nicht das beste Mittel um ein Programm verständlich und wartbar zu halten.

    cu André



  • Achso, ok das war mir ja schon klar. Ich dachte nur man könnte damit auch einen richten Programmabsturz herbeiführen oder so, aber im schlimmsten Fall wird also die falsche Funktion, die man vermutlich nicht haben wollte, aufgerufen?



  • C++. schrieb:

    Achso, ok das war mir ja schon klar. Ich dachte nur man könnte damit auch einen richten Programmabsturz herbeiführen oder so, aber im schlimmsten Fall wird also die falsche Funktion, die man vermutlich nicht haben wollte, aufgerufen?

    Oh, je nach dem wie die Unterschiede zwischen den Methoden sind, würde ich nicht nur von einem "falsche Funktion" reden. Manchmal ist ein Absturz besser als das falsche Ergebnis einer Funktion.


Anmelden zum Antworten