【问题标题】:Call base member function implementation through member function pointer to virtual function [duplicate]通过指向虚函数的成员函数指针调用基成员函数实现[重复]
【发布时间】:2015-06-28 06:26:43
【问题描述】:

我有一种情况,我想要一个指向避免动态分派的虚函数的成员函数指针。见下文:

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

出于好奇,我想要这样做的原因是派生类实现使用实用程序类来记忆(添加缓存)基类实现。实用程序类需要一个函数指针,但当然,函数指针会动态分派给最派生的类,我会得到一个无限递归。

是否有一种语法可以让我重现我可以使用x-&gt;Base::foo() 但通过函数指针实现的静态调度行为?

【问题讨论】:

    标签: c++ member-function-pointers


    【解决方案1】:

    您想要的属性没有独立的“成员函数指针”。最接近绑定成员函数的是闭包:

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

    如果你的类Base 是一个特殊的一次性用例并且在你的控制之下,你可能应该向它添加某种“接受访问者”功能,这样你就可以动态传递成员调用者,比如@ 987654324@等。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();});
    }
    

    【讨论】:

    • Demo.
    • 我可以想象 lambda 会如何提供帮助,但我不明白“接受”的目的......?演示还打印“派生”,而我想要“基础”……我错过了什么吗?
    • 在演示中,需要调用返回的函子:p-&gt;accept([](X * that){that-&gt;X::foo();})(); 按预期打印基数。仍然不确定从接受中获得了什么好处,你能告诉我吗?
    • @SimonD:好吧,我在想,如果您最初希望使用函数指针,那么您需要一种机制来动态地 决定调度目标。 accept 结构也允许这样做,例如您可以制作一个访客容器,然后随机接受其中一个。
    【解决方案2】:

    您可以像这样强制对Base* 进行切片:

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

    【讨论】:

    • 有趣...但这实际上调用了 Base 复制构造函数,因此仅在某些情况下适用。如果 Base 有私有复制构造函数或任何纯虚函数,则此解决方案将不适用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-06
    • 2010-12-01
    相关资源
    最近更新 更多