Zeiger auf virtuelle Memberfunktionen
-
Hallo,
weiß jemand ob man Zeiger auf virtuelle Methoden erstellen und diese im Konstruktor der Basisklasse initialisieren kann, sodass der Zeiger automatisch auf die richtige "überschriebene" virtuelle Methode der abgeleiteten Klasse zeigt?
z.B.: Gegeben ist die Basisklasse A mit einer virtuellen Memberfunktion f(). Im Konstruktor dieser Klasse wird ein Zeiger auf die Funktion f() erstellt. Nun wird von dieser Klasse eine weitere Klasse B abgeleitet. In dieser wird die Funktion f() neu-definiert. Im Konstruktor der Klasse B wird der Konstruktor der Klasse A aufgerufen (a la "B() : A() {}" ). Zeigt der Zeiger dann auf &A::f oder auf &B::f? (ich glaube zwar, dass der Zeiger auf &A::f zeigen wird, weil virtuelle Methoden innerhalb von Konstruktoren nicht (richtig) funktionieren, bin mir aber nicht ganz sicher)
mfg
Alex
-
Erstens: Zeiger auf memberfunktionen sind ziemlich komplex. (http://www.parashift.com/c++-faq-lite/pointers-to-members.html Da gibt es jede Menge informationen über Member Pointer)
Und wenn ich das richtig verstanden habe willst du sowas hier machen? :
#include <iostream> using namespace std; class A { public: A() { f_r=&A::f; } virtual ~A() {} virtual void f() { cout<<"In A"<<endl; } virtual void call() {(this->*f_r)(); } void (A::*f_r)(); }; class B: public A { public: void call() { (this->*f_r)(); } void f() { cout<<"In B"<<endl; } }; int main(int, char**) { A* o; o=new B(); o->call(); (o->*(o->f_r))(); delete o; }Bei mir gibt das 2 mal "In B" aus.
EDIT: Am Ende muss natürlich noch delete o stehen, und der Destruktor von A muss virtuel sein. Geändert.
-
Meinst du so?
#include<iostream> class Base { void (Base::*mem_fun)(); public: Base():mem_fun(&Base::virt_func) {} virtual void virt_func() { std::cout << "Base\n"; } void call() { (this->*mem_fun)(); } }; class Derived: public Base { public: virtual void virt_func() { std::cout << "Derived\n"; } }; int main() { Base base; base.call(); Derived derived; derived.call(); Base *ptr = &base; ptr->call(); ptr = &derived; ptr->call(); }Das sollte funktionieren, weil der Compiler bei virtuellen Funktionen den this-Zeiger "übersetzt", d.h. es die virtuellen Funktionen haben passende Adressen, damit man durch ein paar passende Additionen auf den this-Zeiger zu der passenden Funktion kommt. Ich weiß aber gerade nicht auswendig, ob das vom Standard garantiert ist oder nur bei Compilern funktioniert die virtuelle Funktionen mittels V-Table implementieren (das sind praktisch alle).
Die Frage ist natürlich, wozu man das braucht. Man hat hier praktisch die Funktion des V-Tables nachprogrammiert (bzw. genutzt), also genau das gemacht, was der Compiler beim Aufruf virtueller Funktionen sowieso schon tut. Oder habe ich dich falsch verstanden und du meintest das anders?
edit: zu spät.
-
@SeppJ und @pyhax: ja ihr habt das Richtig verstanden.
Ich wollte für mein Projekt ein kleines Callback-Mechanismus implementieren und es war halt wichtig für mich zu wissen, ob ich bei jeder Klasse die abgeleitete Funktion an ein Event "Bind()"en muss oder ob das auch mit weniger Boilerplate Code geht (und ich nur in der Basisklasse "Bind()"en muss).
Vielen Dank für die Antworten, ich bin positiv überrascht
.
Eine Frage hätte ich noch: ihr benutzt beide eine separate Funktion zum Aufrufen von der Funktion mittels Zeiger. Ist das nur guter Stil oder steckt da irgendeine "technische Nuance" dahinter?nochmal Dankeschön für die Antworten!
-
Ich kenne mich da nicht so aus ... Finde es bloß praktischer einfach this->call() aufzurufen als (this->*f_p)(), und außerdem verhindert das das jeder zugriff auf den Funktionspointer hat (man kann den Funktionspointer dann private machen)
-
ok, danke das wollte ich wissen
