Rein virtuelle Funktion in Konstruktor



  • asc schrieb:

    ingobulla schrieb:

    Wenn ich das so richtig sehe, kann der Konstruktor von D so nicht funktionieren, da zuerst der Konstruktor von B aufgerufen wird, der f aufruft und f greift dann auf data members von D zu, die erst noch initialisiert werden.

    Genau.

    Falsch, f wird zu diesem Zeitpunkt zu B::f aufgelöst (12.7§3), was dir undefiniertes Verhalten (bzw. einen Programmabruch mit der Meldung "pure virtual function called") einbringt.



  • Bashar schrieb:

    Falsch,...

    Stimmt, war zu schnell und habe weder das pure-virtual gesehen, noch eine sinnvolle Erklärung geliefert (Oben geändert).



  • Bashar schrieb:

    Falsch, f wird zu diesem Zeitpunkt zu B::f aufgelöst (12.7§3), was dir undefiniertes Verhalten (bzw. einen Programmabruch mit der Meldung "pure virtual function called") einbringt.

    Auf was bezieht sich denn (12.7§3)?



  • Auf den C++-Standard, ISO/IEC 14882:1998. Abschnitt 12.7, Absatz 3 🙂



  • asc schrieb:

    Bashar schrieb:

    Falsch,...

    Stimmt, war zu schnell und habe weder das pure-virtual gesehen, noch eine sinnvolle Erklärung geliefert (Oben geändert).

    Das hat mit pure-virtual nix zu tun, in B::B wird niemals D::f aufgerufen werden. Ob B::f dabei pure ist oder nicht spielt keine Rolle.
    Wenn es nicht pure wäre, würde es halt keinen Fehler geben, und es würde B::f aufgerufen (was es ja dann geben muss, weil B::f ja implementiert sein muss, wenn es nicht pure ist).



  • asc schrieb:

    Wenn man nicht die Logik durch überdenken des Konzeptes anpassen kann, ist der einzige mir auf Anhieb einfallende Weg der, die Initialisierung auf einen späteren Zeitpunkt zu verschieben. In einem solchen Fall gehe ich persönlich dazu über den Konstruktor nicht-public zu machen, sondern über Fabrikmethoden (z.B. eine statische Funktion die ein Objekt erzeugt) zu verwenden. Letztere kann nach dem Konstruktoraufruf noch weitere Initialisierungen durchführen.

    Wenn ich das richtig verstehe, wuerde das dann wie folgt aussehen:

    class D : public B
    {
        D() : B() { // initialisiere irgendwelche data members }
        void f();
    public:
        static D* create() {
            D* d = new D();
            d->f();
            return d;
        }
        ...
    }
    

    Ist das so gemeint? Mein Problem hier ist, dass, wenn ich aus B weitere Klassen ableite, die von der Struktur wie D sind, ich in deren Fabrikmethode immer dran denke muss, f() aufzurufen. Daher wuerde ich den Aufruf von f() lieber irgendwie in B behalten.



  • struct BBase
    {
        virtual void f (void) = 0;
    };
    
    template <class C>
        struct B : BBase
    {
        static C* create (void)
        {
            std::auto_ptr <C> result (new C);
            result->f ();
            return result.release ();
        }
    };
    
    struct C : B <C>
    {
        void f (void) { ... }
        C (void) { ...}
    };
    


  • ingobulla schrieb:

    Ist das so gemeint? Mein Problem hier ist, dass, wenn ich aus B weitere Klassen ableite, die von der Struktur wie D sind, ich in deren Fabrikmethode immer dran denke muss, f() aufzurufen.

    Ohne deinen Fall genau zu kennen, kann ich dir nur sagen, das es nur 2 Lösungsansätze gibt:
    a) Die Basisklasse über dessen Konstruktor gleich richtig initialisieren (wenn möglich)
    b) Über Fabrikmethoden (Und ja, dann kannst du f() auch vergessen)

    In der Regel würde ich a) ohnehin b) vorziehen.

    Edit: Okay, das "Curiously Recurring Template Pattern" habe ich tatsächlich nicht berücksichtigt.



  • audacia schrieb:

    struct BBase
    {
        virtual void f (void) = 0;
    };
    
    template <class C>
        struct B : BBase
    {
        static C* create (void)
        {
            std::auto_ptr <C> result (new C);
            result->f ();
            return result.release ();
        }
    };
    
    struct C : B <C>
    {
        void f (void) { ... }
        C (void) { ...}
    };
    

    Das scheint mir die Loesung des Problems. Hat diese Art von Fabrikmethoden-Konstrukt eigentlich einen Namen?



  • ingobulla schrieb:

    Das scheint mir die Loesung des Problems. Hat diese Art von Fabrikmethoden-Konstrukt eigentlich einen Namen?

    Dieses Templatekonstrukt nennt sich "Curiously Recurring Template Pattern" (Kurios weil es sich auf den Datentyp der Kindklasse bezieht). Dies ist aber unabhängig davon ob man es als Factory oder für andere Dinge verwendet.



  • asc schrieb:

    (Kurios weil es sich auf den Datentyp der Kindklasse bezieht).

    Wikipedia ist anderer Meinung:

    Wikipedia schrieb:

    The name of this idiom was coined by Jim Coplien[1], who had observed it in some of the earliest C++ template code.

    Ich würde es mit "seltsamerweise immer wieder auftauchendes Template-Pattern" übersetzen.



  • audacia schrieb:

    asc schrieb:

    (Kurios weil es sich auf den Datentyp der Kindklasse bezieht).

    Wikipedia ist anderer Meinung:

    Gerade mit dem von dir angegebenen Zitat kann ich keinen Widerspruch zu meiner Beschreibung sehen. Zudem fand ich die Erklärung im "C++ Templates" Buch deutlich besser.

    Wikipedia schrieb:

    Ich würde es mit "seltsamerweise immer wieder auftauchendes Template-Pattern" übersetzen.

    "Kurios wiederholendes Templatepattern" hört sich für mich persönlich besser an.



  • asc schrieb:

    Gerade mit dem von dir angegebenen Zitat kann ich keinen Widerspruch zu meiner Beschreibung sehen.

    Das Zitat im Kontext des Satzes selbst macht deutlich, daß die Bezeichnung "Curiously Recurring Template Pattern" nicht deskriptiv ist; sie bezieht sich nicht auf das Pattern selbst, sondern auf das Phänomen desselben.

    asc schrieb:

    Zudem fand ich die Erklärung im "C++ Templates" Buch deutlich besser.

    Dann laß mal sehen.

    asc schrieb:

    "Kurios wiederholendes Templatepattern" hört sich für mich persönlich besser an.

    Tatsächlich? Mit meinem Sprachverständnis (und vermutlich auch mit der deutschen Grammatik) ist dieser Satz nicht so recht vereinbar 😉 Was soll, von der Unbekanntheit des englischen Originals ausgehend, "kurios wiederholendes Pattern" denn aussagen? Fehlt bei "wiederholen" nicht ein Objekt?
    Übrigens ist LEO bei "couriously" und "recur" recht eindeutig: weder "kurios" noch "wiederholend" sind adäquate Übertragungen.

    Außerdem finde ich die Bezeichnung "Curiously Recurring Template Pattern" ohnehin meidenswert, da sie nicht deskriptiv ist. Obiges Codebeispiel kann ebensogut als Mixin eingeordnet werden.


Anmelden zum Antworten