Rein virtuelle Funktion aufrufen



  • Und noch ne Frage.

    Kann ich im Konstruktor meiner abstrakten Basisklasse den keine Funtkion aufrufen die rein virtuell deklariert ist.

    Kann ja von dieser Klasse eh kein Objekt direkt erzeugen. Kann ja nur ein Objekt erzeugen einer abgeleiteten Klasse und dort ist die Funktion ja dann definiert.

    Oder habe ich da noch was übersehen?



  • Kann ich im Konstruktor meiner abstrakten Basisklasse den keine Funtkion aufrufen die rein virtuell deklariert ist.

    Nein, das kannst Du nicht. Das abgeleitete Objekt ist ja noch nicht konstruiert und desshalb existiert auch noch keine impl.

    Simon



  • Gut. Danke.



  • Wahrscheinlich verstehe ich die Frage falsch aber warum sollte man im Konstruktor einer abstrakten Klasse keine abstrakten Funktionen dieser Klasse aufrufen können?


  • Administrator

    connan schrieb:

    Wahrscheinlich verstehe ich die Frage falsch aber warum sollte man im Konstruktor einer abstrakten Klasse keine abstrakten Funktionen dieser Klasse aufrufen können?

    Weil zu diesem Zeitpunkt, wo man im Konstruktor der abstrakten Klasse ist, der Teil des Objektes wo die Funktion implementiert ist, noch nicht existiert. Oder vielleit mit ein wenig Code und Kommentaren veranschaulicht:

    struct Base
    {
      Base()
      {
        // Hier wurde der Teil Derived noch nicht gebaut.
        // Die Implementierung von foo ist nicht bekannt.
        // Wir haben noch immer nur ein Objekt Base.
      }
    
      virtual void foo() = 0;
    };
    
    struct Derived
      : Base
    {
      Derived()
        : Base()
      {
        // Jetzt ist der Basekonstruktor durch.
        // Ein Objekt Derived wurde nun gebaut.
        // Nun ist die Funktion foo auch vorhanden.
      }
    
      virtual void foo() { }
    };
    

    Man sollte grundsätzlich NIE eine virtuelle Funktion aus dem Konstruktor aufrufen. Sowas ist sehr gefährlich.

    Grüssli



  • Du hast natürlich Recht (musste es einfach mal probieren) 🙂
    Komisch das ich das Problem noch nie hatte, hätte ich mir für mich gut vorstellen können sowas zu versuchen 😉
    Scheint aber insofern nicht 'gefährlich' zu sein weil der Linker sofort meckert.



  • Scheint aber insofern nicht 'gefährlich' zu sein weil der Linker sofort meckert.

    Falsch.
    Bei virtuellen (aber nicht rein- virtuellen) Funktionen wird die Implementation der Basis Klasse aufgerufen. Ein nicht erwünschtes Verhalten, welches vermutlich auch nicht offensichtlich ist.
    Bei rein virtuellen Funktionen gibts ein Fehler der Runtime (z.B. R6025 http://support.microsoft.com/kb/125749).

    Simon


  • Administrator

    Oder wieder mit etwas Code:

    struct Base
    {
      Base()
      {
        foo();
      }
    
      virtual void foo() = 0 { }
      //                 ^^^^^^^
      // Für alle die es noch nicht wussten, das ist erlaubt :)
    };
    
    struct Derived
      : Base
    {
      int x;
    
      Derived()
      {
      }
    
      virtual void foo()
      {
        Base::foo();
        x = 0;
      }
    };
    

    Kompiliert und linkt 😉

    Grüssli



  • Man bekommt es auch ohne Definition compiliert + gelinkt, und dann entsprechend undefiniertes Verhalten wenn man es ausführt:

    #include <iostream>
    
    class foo
    {
    public:
    	foo();
    	virtual void bar() = 0;
    };
    
    class foo_impl : public foo
    {
    public:
    	virtual void bar()
    	{
    		std::cout << "foo_impl::bar\n";
    	}
    };
    
    void call_bar(foo* f)
    {
    	f->bar();
    }
    
    foo::foo()
    {
    	call_bar(this);
    }
    
    int main()
    {
    	std::cout << "1\n";
    	foo_impl f;
    	std::cout << "2\n";
    	return 0;
    }
    

    Output mit VC9:

    1
    R6025
    - pure virtual function call
    


  • Dravere schrieb:

    Oder wieder mit etwas Code:

    struct Base
    {
      Base()
      {
        foo();
      }
    
      virtual void foo() = 0 { }
      //                 ^^^^^^^
      // Für alle die es noch nicht wussten, das ist erlaubt :)
    };
    

    Wusste ich nicht 😉
    Wo ist da aber noch der Unterschied zu einer 'normalen' virtuellen Funktion?


  • Mod

    Gar keiner!
    Das schöne ist aber, dass man eine Funktion als pur-virtuell angeben kann aber dennoch eine Standardbehandlung hinterlegen kann.

    Es ist erlaubt die rein virtuelle Funktion einer Basisklasse aufzurufen...



  • Logisch ist das erlaubt... fragt sich nur wann... und was effektiv für eine implementation aufgerufen wird...



  • @connan:
    Der Unterschied ist ... eine "pure" Funktion, egal ob mit Implementierung oder ohne, muss erst nochmal überschrieben werden, damit man die Klasse instanzieren kann.

    D.h.
    a) eine Klasse "Base" die selbst eine Funktion "pure" definiert kann nicht instanziert werden, auch wenn sie die Funktion implementiert
    b) eine Klasse "X" die direkt von "Base" abgeleitet ist, kann nur instanziert werden, wenn sie die Funktion überschreibt
    c) eine Klasse "Y" die indirekt von "Base" abgeleitet ist, kann nur instanziert werden, wenn sie selbst, oder eine der Klassen "zwischen" "Base" und "Y" die Funktion überschreibt

    Das kann man z.B. auch schön ausnutzen, um eine Klasse nicht-instanzierbar zu machen, ohne sonstige zusätzlichen Restriktionen, indem man den Destruktor "pure" macht. Natürlich muss man den Destruktor trotzdem implementieren.

    Da jede abgeleitete Klasse den virtuellen Destruktor "überschreibt" (wenn man keinen selbst definiert bekommt man ja einen default-generierten), kann jede abgeleitete Klasse instanziert werden. Die Basisklasse selbst allerdings nicht.

    @theta:
    Wenn du eine Funktion "voll qualifiziert" aufrufst, also ptr->Base::bar(), dann ist der Aufruf nie virtuell. So klannst du in Derived::bar() auch Base::bar() aufrufen, obwohl Base::bar() virtuell ist.
    (Ich weiss nicht ob "voll qualifiziert" der richtige Begriff ist, aber ich hoffe es ist klar was gemeint ist)



  • hustbaer schrieb:

    @connan:
    Der Unterschied ist ... eine "pure" Funktion, egal ob mit Implementierung oder ohne, muss erst nochmal überschrieben werden, damit man die Klasse instanzieren kann.

    Ok, den lass ich gelten 😉
    Danke euch allen für die netten Erklärungen 🙂

    Martin Richter schrieb:

    Gar keiner!
    Das schöne ist aber, dass man eine Funktion als pur-virtuell angeben kann aber dennoch eine Standardbehandlung hinterlegen kann.

    Es ist erlaubt die rein virtuelle Funktion einer Basisklasse aufzurufen...

    Super Idee, ich suche schon lange nach einer Stelle um default code für Interfaces abzulegen. Ich hoffe nur das lässt sich über VCCodeClass auflösen.



  • Funktioniert perfekt 🙂
    Die default Implementierung steht ganz normal in VCCodeFunction::BodyText.


Anmelden zum Antworten