2015-04-21 76 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