2015-04-21 23 views
5

Ho una situazione in cui voglio un puntatore di funzione membro a una funzione virtuale che evita l'invio dinamico. Vedi sotto:Implementazione della funzione membro della base di chiamata tramite il puntatore della funzione membro alla funzione virtuale

struct Base 
{ 
    virtual int Foo() { return -1; } 
}; 

struct Derived : public Base 
{ 
    virtual int Foo() { return -2; } 
}; 

int main() 
{ 
    Base *x = new Derived; 

    // Dynamic dispatch goes to most derived class' implementation  
    std::cout << x->Foo() << std::endl;  // Outputs -2 

    // Or I can force calling of the base-class implementation: 
    std::cout << x->Base::Foo() << std::endl; // Outputs -1 

    // Through a Base function pointer, I also get dynamic dispatch 
    // (which ordinarily I would want) 
    int (Base::*fooPtr)() = &Base::Foo; 
    std::cout << (x->*fooPtr)() << std::endl; // Outputs -2 

    // Can I force the calling of the base-class implementation 
    // through a member function pointer? 
    // ...magic foo here...? 

    return 0; 
} 

Per i curiosi, il motivo per cui voglio che questo è perché l'implementazione della classe derivata sta usando una classe di utilità per Memoize (aggiungere una cache in giro) l'implementazione della classe base. La classe di utilità utilizza un puntatore a funzione, ma, naturalmente, il puntatore di funzione viene inviato dinamicamente alla classe più derivata e ottengo una ricorsione infinita.

C'è una sintassi che mi consente di riprodurre il comportamento di invio statico che posso ottenere con x->Base::foo() ma tramite un puntatore di funzione?

risposta

1

Si potrebbe forzare l'affettamento del Base* in questo modo:

std::cout << (static_cast<Base>(*x).*fooPtr)() << std::endl; // Outputs -1 
+0

Interessante ... ma questo in realtà chiama la Bas Il costruttore di copie è quindi applicabile solo in alcuni casi. Se Base ha un costruttore di copie privato o qualsiasi funzione virtuale pura, questa soluzione non verrà applicata. – SimonD

0

Non c'è "puntatore a funzione membro" free-standing con la proprietà che si desidera. La cosa più vicina ad una funzione di membro associato è una chiusura:

Base * x = new Derived; 
auto f = [x]() { x->Base::Foo(); } 
f(); 

Se la classe Base è una speciale, una tantum caso d'uso ed è sotto il vostro controllo, probabilmente si dovrebbe aggiungere una sorta di "accettare visitatore" la funzione ad esso in modo da poter passare in modo dinamico i chiamanti membri, come x->accept(foo_caller); ecc Un esempio in C++ 14:

struct X 
{ 
    template <typename F> 
    auto accept(F && f) 
    { 
     return [this, &f](auto &&... args) { 
      return f(this, std::forward<decltype(args)>(args)...); }; 
    } 

    virtual void foo() const { std::cout << "base\n"; } 
}; 

Usage:

void call_static_foo(X * p) 
{ 
    p->accept([](X * that){that->X::foo();}); 
} 
+0

[Demo] (http://ideone.com/h4QXUi). –

+0

Posso immaginare come potrebbe aiutarmi un lambda ma non capisco lo scopo di "accettare" ...? Anche la demo stampa 'derivata', mentre io voglio 'base' ... mi manca qualcosa? – SimonD

+0

Nella demo, il functor restituito doveva essere chiamato: 'p-> accept ([] (X * that) {that-> X :: foo();})();' Stampa base come previsto. Non sono ancora sicuro di quale vantaggio si possa ottenere accettando, potresti parlarmi? – SimonD

Problemi correlati