2015-04-21 74 views
5

我有一種情況,我想要一個成員函數指針指向一個虛擬函數,以避免動態分派。請看下圖:通過成員函數指針調用基礎成員函數實現指向虛函數

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

對於好奇,我想這是因爲派生類的實現使用工具類memoize的原因(添加緩存周圍)的基類實現。實用程序類採用函數指針,但是,當然,函數指針動態分派到大多數派生類,並且我得到無限遞歸。

是否有一種語法可以讓我重現靜態調度行爲,我可以通過x->Base::foo()來實現,但通過函數指針?

回答

1

你可能會迫使Base*這樣的片斷:

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

有趣......但是這實際上是調用了巴斯e複製構造函數僅適用於某些情況。如果Base具有私有拷貝構造函數或任何純虛函數,則此解決方案將不適用。 – SimonD

0

有沒有獨立的「成員函數指針」與你想要的屬性。最接近的東西綁定的成員函數是一個閉包:

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

如果您Base類是特殊的,一次性的使用情況,並在你的控制之下,很可能需要添加某種「接受訪問者」功能,它使您可以在成員呼叫者通過動態,像x->accept(foo_caller);等在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"; } 
}; 

用法:

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

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

+0

我能想象lambda會如何幫助,但我不明白「接受」的目的......? 此外演示打印'派生',而我想'基地'...我錯過了什麼? – SimonD

+0

在演示中,需要調用返回的函數: 'p-> accept([](X * that){that-> X :: foo();})();' 按預期打印基底。 仍然不確定從接受中獲得的優勢是什麼,你可以通過它說說我嗎? – SimonD