2015-04-21 16 views
5

Mam sytuację, w której chcę wskaźnik funkcji członka do funkcji wirtualnej, która unika dynamicznego wysyłania. Patrz poniżej:Implementacja funkcji członka podstawowego za pomocą wskaźnika funkcji członka do funkcji wirtualnej

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

dla ciekawskich, powodem chcę to dlatego, że pochodzi implementacja klasy stosuje klasę użytkową do memoize (dodać około cache) realizację bazowej klasy. Klasa narzędzi przyjmuje wskaźnik funkcji, ale oczywiście wskaźnik funkcji dynamicznie odsyła do najbardziej wyprowadzonej klasy i otrzymuję nieskończoną rekursję.

Czy istnieje składnia, która pozwala mi odtworzyć zachowanie statyczne wysyłki, które można uzyskać za pomocą x->Base::foo(), ale za pomocą wskaźnika funkcji?

Odpowiedz

1

Można wymusić krojenie na Base* tak:

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

Ciekawe ... ale to faktycznie wywołuje Bas e Konstruktor kopiowania ma zastosowanie tylko w niektórych przypadkach. Jeśli baza ma prywatny konstruktor kopii lub dowolne czyste funkcje wirtualne, to rozwiązanie nie będzie miało zastosowania. – SimonD

0

Nie ma wolnostojący „wskaźnik funkcji członek” z właściwością chcesz. Najbliższa rzecz do oprawionego funkcji członka jest zamknięcie:

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

Jeśli klasa Base jest specjalną, jednorazową przypadków użycia i jest pod kontrolą, należy prawdopodobnie dodać jakiś rodzaj „przyjąć gościa” funkcja do niej, dzięki czemu można przejść w dzwoniących członkowskich dynamicznie, jak x->accept(foo_caller); itp Przykładem w 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"; } 
}; 

Zastosowanie:

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

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

+0

Mogę sobie wyobrazić, w jaki sposób lambda mogłaby pomóc, ale nie rozumiem celu "akceptacji" ...? Również wersja demonstracyjna drukuje "pochodną", podczas gdy ja chcę "bazę" ... czy czegoś brakuje? – SimonD

+0

W wersji demonstracyjnej zwrócony funktor musi być wywołany: 'p-> accept ([] (X * that) {that-> X :: foo();})();' Drukuje bazę zgodnie z oczekiwaniami. Nadal nie wiesz, jaką przewagę zyskujesz z akceptacji, czy możesz mnie o tym przekonać? – SimonD

Powiązane problemy