2014-12-10 15 views
11

Wenn ich eine virtuelle Funktion foo() zuerst in einer Basisklasse definiert B und dann in einer abgeleiteten Klasse überschrieben D, wie kann ich die Adresse B::foo in einem Zeiger-to-Mitgliedsgeschäft -Funktion in einer Weise, dass beim Aufruf, würde sich der Anruf als eine qualifizierte ID-Aufruf (wie pd->B::foo()) verhalten?Qualified-id Anruf an Basisfunktion über Zeiger

Beispiel:

struct B { 
    virtual int foo() { return 1; } 
}; 

struct D: public B { 
    virtual int foo() { return 2; } 
}; 

int main(int argc, char * argv[]) { 
    D* pd = new D(); 
    int (B::*pf)() = &B::foo; 
    int r = (pd->*pf)(); 
    return 0; 
} 

Dies würde D::foo() nennen. Kann ich pf auf eine Weise initialisieren, dass die (pd->*pf)()B::foo() aufrufen würde, selbst wenn der dynamische Typ pd eine Klasse ist, die foo() überschreibt?

(Bevor jemand fragt, ich will das nicht wirklich tun, ich bin nur neugierig, wenn es möglich ist.)

+1

Cheap hack: 'int (* fp) (B &) = [] (B & b) {return b.B :: foo(); }; ' –

Antwort

0

Warum nicht einfach tun:

pd->B::foo() 
+5

Das sollte wirklich ein Kommentar sein, aber das beiseite, das OP hat es bereits beantwortet. – StoryTeller

0

Ich glaube nicht, Sie können.
ich bei mir habe meinen Standard nicht, aber die Vararg mit hacke die Werte des Zeigers auf Elementfunktionen http://ideone.com/bRk7mG drucken:

#include <iostream> 
#include <cstdarg> 
using namespace std; 

struct Test 
{ 
    void foo() {}; 
    virtual void bar() {}; 
    virtual void bar2() {}; 
    virtual void bar3() {}; 
}; 

void print_hack(int dummy, ...) 
{ 
    va_list argp; 
    va_start(argp, dummy); 
    long val = va_arg(argp, long); 
    cout << val << endl; 
    va_end(argp); 
} 

int main() { 
    print_hack (0, &Test::foo); 
    print_hack (0, &Test::bar); 
    print_hack (0, &Test::bar2); 
    print_hack (0, &Test::bar3); 
    return 0; 
} 

Es scheint, wie der Wert in dem Zeiger (zumindest für GCC gespeichert) ist der Index in der virtuellen Tabelle der Objekte.
Für nicht-virtuelle Funktionen scheint es wie ein normaler Funktionszeiger.

Grundsätzlich sind Sie gezwungen, dynamisch zu versenden, wenn Sie eine Zeiger-zu-Stab-Funktion verwenden, die zumindest soweit ich weiß eine virtuelle Funktion besitzt.

0

ich mit snakedoctor zustimmen, sollten Sie tun:

int r = pd->B::foo() 

Es ist nur ein Aufruf der Methode der Mutter.

1

Ich stimme StoryTeller zu, ich glaube nicht, dass es in irgendeiner standardkonformen Weise möglich ist. Wenn das, was Sie wirklich erreichen wollen, entweder die Basisklassenimplementierung oder abgeleiteten Klasse Implementierung aufrufen zu können, ist die gleiche Funktion Zeiger verwenden, das Beste, was ich empfehlen kann, ist dies:

struct B { 
    virtual int foo() { return fooB(); } 
    int fooB() { return 1; } 
}; 

struct D: public B { 
    virtual int foo() { return 2; } 
}; 

int main(int argc, char * argv[]) { 
    D* pd = new D(); 
    int (B::*pf)() = &B::fooB; 
    int r = (pd->*pf)(); 
    return 0; 
} 

Da die Funktion Zeigertyp das ist Gleichgültig, ob eine Funktion virtuell ist oder nicht. Wenn Sie dann eine nicht-virtuelle Funktion in der Basisklasse erstellen, können Sie ihre Adresse direkt übernehmen.