Aufruf virtueller Methoden im Constructor



  • Hallo,

    ich nähere mich an C++ von Delphi herran und habe ein Verständnisproblem:

    class A { 
    public: 
      A() {Test();};
      virtual Test(){ printf("Base"); };
    }; 
    
    class B: public A { 
    public: 
      virtual void Test(){ printf("Abgeleitet"); }; 
    };
    

    Wenn ich o.g. eine Klasse B erzeuge wird "Base" ausgegeben, obwohl B ja Test() überschreibt. Ich würde da "Abgeleitet" erwarten. Unter Delphi ist dieses nicht der Fall und im Rahmen dessen,
    was unter C++ "späte Bindung" heißt, sollte es auch nicht sein, oder?
    Wie spät setzt die Bindung denn ein?

    Ein Aufruf später (ausserhalb des Constructors) liefert das erwartete Ergebniss.
    Sicher könnte ich den Constructor von B überschreiben und dort "Test();" einfügen, allerdings müsste ich das dann ja für jede abgeleitete Klasse tun, oder ?

    Mache ich etwas falsch, oder gibt C++ das einfach nicht her?

    Gruß
    Sascha



  • Die Sache ist einfach folgende:
    Im Konstruktor von A ist das Objekt ein A (und kein B). Damit wird auch nur A::Test aufgerufen, auch wenn du am Ende ein B-Objekt erzeugst.
    Und das ist auch gut so, stell dir mal vor, B::Test würde auf ein Member von B zugreifen. Da aber die Basisklasse von B (nämlich A) vor diesem Member initialisiert wird, würde ein B::Test im Ctor von A auf ein Objekt zugreifen, das noch garnicht existiert. Autsch...



  • Danke für die Antwort.

    Da lob ich mir Delphis Compilermagie 😉

    Gibt es denn eine Möglichkeit unter C++ dieses Problem zu lösen?
    Sprich beim Erzeugen eine Methode des entgültigen Objekts aufzurufen, ohne
    jedesmal den Konstrucktor überschreiben zu müssen?



  • Zur Erzeugungszeit, also während der Basis Constructor aufgerufen wird,
    ist die instanz eine instanz von A. Wenn du test() pur virtuell definiert hättest,
    würde dir der linker nicht erlauben diese im Base class ctor aufzurufen.

    Es wäre ja auch fatal, dies zu erlauben, da B::test vielleicht auf Member zugreift die nur B hat, aber A nicht. bzw. erst vom ctor von B initialisiert
    werden müssen.

    Nach der Konstruktion ist das natürlich alles kein Problem mehr.

    EDIT: Der Pumuckl der Lauser! 😡 War wieder schneller... 😉

    EDIT2:
    Jetzt würd mich aber interessieren, wie das bei Delphi gehen soll?
    Diese Einschränkung ist vollkommen logisch.
    Ich kann mir nicht vorstellen, dass du auf nicht initialisierte Member
    in delphi zugreifen darfst. Initialsiert das in ner anderen Reihenfolge?
    Kannst du da mal elaborieren??



  • Hallo,

    wie Delphi das genau macht, weiß ich auch nicht.
    Allerdings ruft der abgeleitete Konstruktor quasi explitiz den Vorgänger auf,
    womit folgende Aufrufe im Kontext der abgeleiteten Klasse laufen.

    Die Klasse ist also gleich vom abgeleitetem Typ und nicht wie wohl in C++
    erst Klasse 1 dann Klasse 2...

    Gruß



  • Du kannst in C++ aus keinem Konstruktor zuverlässig virtuelle Funktionen aufrufen. Ich glaube nicht, das es mit B-Ctor besser werden würde.

    Ich habe in meinem Projekt ein ähnlichen Fall. Das einfachste wäre, eine create-Funktion zu bauen, die die nötigen Schritte veranlasst. So in etwa:

    template<typename T>
    T* create()
    {
         T* t = new T;
         t->Test();
         return t;
    }
    
    // irgendwo...
    B* b = create<B>();
    

    Das man aber aus dem Ctor virtuelle Funktionen (erfolgreich) aufrufen können soll, ist bereits ein Thema im C++-Standard-Komitee. Ich weiß nur nicht, ob es da schon konkrete Lösungen gibt.



  • Newbee2 schrieb:

    Da lob ich mir Delphis Compilermagie 😉

    Und ich verfluche sie. VCL-Style Klassen [mit __fastcall...] verhalten sich unter C++ anders als normale C++ Klassen.

    Newbee2 schrieb:

    Gibt es denn eine Möglichkeit unter C++ dieses Problem zu lösen?
    Sprich beim Erzeugen eine Methode des entgültigen Objekts aufzurufen, ohne
    jedesmal den Konstrucktor überschreiben zu müssen?

    Ja, mit einen kleinen Trick. Du erzeugst die Objekte über eine sogenannte "Factorymethode" (z.b. Konstruktor privat machen, und die Objektanlage über eine statische Methode erledigen, die nach dem Konstruktoraufruf die entsprechende Methode aufruft, und anschließend das Objekt zurückgibt).

    cu André


Anmelden zum Antworten