2014-12-10 12 views
11

Se ho una funzione virtuale foo() prima definito in una classe base B e poi override in una classe derivata D, come posso memorizzare l'indirizzo di B::foo in un membro puntatore a -funzione in modo tale che al momento della chiamata, la chiamata si comporti come una chiamata id idivisa (come pd->B::foo())?qualificato-id per funzione base tramite puntatore

Esempio:

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; 
} 

Questo avrebbe chiamato D::foo(). Posso inizializzare pf in modo tale che lo (pd->*pf)() chiamerebbe B::foo() anche se il tipo dinamico di pd è una classe che sovrascrive lo foo()?

(Prima che qualcuno si chiede, non voglio davvero fare questo, io sono solo curioso di sapere se è possibile.)

+1

Hack economici: 'int (* fp) (B &) = [] (B & b) {ritorno b.B :: pippo(); }; ' –

risposta

0

Perché non basta fare:

pd->B::foo() 
+5

Questo dovrebbe essere un commento, ma a parte questo, l'OP ha già risposto. – StoryTeller

0

non ritengo puoi.
Non ho il mio standard con me, ma usando il vararg Hack per stampare i valori del puntatore a funzioni membro http://ideone.com/bRk7mG:

#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; 
} 

Sembra che il valore memorizzato nel puntatore (almeno per GCC) è l'indice nella tabella virtuale degli oggetti.
Per le funzioni non virtuali sembra un puntatore a funzione regolare.

Fondamentalmente si è obbligati a fare un dispatch dinamico quando si utilizza una funzione pointer-to-member che contiene una funzione virtuale, almeno per quanto ne so.

0

Sono d'accordo con snakedoctor, si dovrebbe fare:

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

E 'solo una chiamata al metodo della madre.

1

Sono d'accordo con StoryTeller, non penso sia possibile in alcun modo conforme agli standard. Se ciò che si vuole veramente raggiungere è quello di essere in grado di chiamare sia l'implementazione della classe base o implementazione della classe derivata utilizzando lo stesso puntatore a funzione, il meglio che posso consigliare è questo:

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; 
} 

Dato il tipo di puntatore a funzione è la lo stesso se una funzione è virtuale o meno, quindi la creazione di una funzione non virtuale nella classe base consente di prendere direttamente il suo indirizzo.