在 Array/Vector 容器中存储虚函数

Storing virual functions in Array/Vector container

我有一个具有共同行为的基础 class 和具有覆盖虚函数的派生 class。但是如果试图将函数指针保存为 std::vector 我会得到错误:

 ISO C++ forbids taking the address of an unqualified or
  parenthesized non-static member function to form a pointer to member function.

我需要这样的东西:

class Base
{
public:
    virtual int fun1(int inp) = 0;
    virtual int fun2(int inp) = 0;
    int init(int inp, std::vector<std::function<int(int)>> Callbacks, int index)
    {
        if (index == 0)
            return Callbacks[0](inp);
        else
            return Callbacks[1](inp);
    }
    int run()
    {
        return init(5, { &fun1, &fun2 }, 0);
    }
};

class A : public Base
{
    int fun1(int inp)
    {
        return inp * 10;
    }
    int fun1(int inp)
    {
        return inp * 100;
    }
};

class B : public Base
{
    int fun1(int inp)
    {
        return inp * 20;
    }
    int fun2(int inp)
    {
        return inp * 200;
    }
};

int main(int argc, char const* argv[])
{
    auto f = new B;
    int e = f->run();
    return 0;
}

有什么方法可以做我想做的事吗?也许我可以以某种方式将虚函数绑定到容器?或者我可以将 lambda 函数设置为虚拟函数吗?当我尝试在 Base class 中声明 lambda 函数时,当我在派生 class 中更改函数时,出现错误:

您将获得一个指向成员的“指针”,语法为 &Class::MemberClass::Member 是成员的“合格”名称)。

这些只是抽象意义上的指针,需要相对于对象取消引用。
您可以使用 ->*.* 运算符来执行此操作,具体取决于左侧是否为指针。
请注意,如果这是相关对象,则必须明确使用 this

&Base::fun1&Base::fun2的类型是int (Base::*)(int),无法转换为std::function<int(int)>

放在一起:

int init(int inp, std::vector<int (Base::*)(int)> Callbacks, int index)
{
    if (index == 0)
        return (this->*Callbacks[0])(inp); // The leftmost parentheses are necessary.
    else
        return (this->*Callbacks[1])(inp);
}

int run()
{
    return init(5, {&Base::fun1, &Base::fun2}, 0);
}

如果你不想限制成员的回调,你可以使用 lambda 函数,捕获 this:

int init(int inp, std::vector<std::function<int(int))> Callbacks, int index)
{
    if (index == 0)
        return Callbacks[0](inp);
    else
        return Callbacks[1](inp);
}

int run()
{
    return init(5, 
                {[this](int i) { return fun1(i); },
                 [](int) { return 567; } }, 
                0);
}

@PaulMcKenzie,谢谢。现在可以使用了:

class Base
{
public:
    std::function<int(int)> fun1;
    std::function<int(int)> fun2;
    int init(int inp, std::vector<std::function<int(int)>> Callbacks, int index)
    {
        if (index == 0)
            return Callbacks[0](inp);
        else
            return Callbacks[1](inp);
    }

    int run()
    {
        return init(5, {&fun1, &fun2}, 0);
    }
};

class B : public Base
{
public:
    B()
    {
        fun1 = fun1B;
        fun2 = fun2B;
    }

private:
    std::function<int(int)> fun1B = [&](int inp)
    {
        return inp * 20;
    };
    std::function<int(int)> fun2B = [&](int inp)
    {
        return inp * 200;
    };
};

int main(int argc, char const *argv[])
{
    auto f = new B();
    int e = f->run();
    assert(e == 5*20);
    return 0;
}

但是上面的例子看起来更正确。

您的代码有几个问题:

  1. 指向成员函数的指针与指向非成员、静态或“自由”函数的指针不同。这意味着这里的类型 std::function<int(int)> 是错误的,因为它意味着自由函数或静态函数。

  2. 成员函数指针的调用和普通的函数调用不一样。你需要 specify the object to which you are calling the member function pointer. Since C++17 you can also invoke the pointer to member function using more generic std::invoke.

  3. 你只需要初始化Callbacks一次(可能在contractor中),然后在run中使用它。

  4. 传递成员函数指针时,您需要语法 &ClassName::MemberFunction,您在函数调用 init(5, {&fun1, &fun2}, 0);.

    中遗漏了它
  5. Base 需要一个 virtual destructor for defined behavior,以防您稍后将子项存储在 Base class 指针中。

以下是根据上述更改的示例代码:

#include <functional> // std::invoke

class Base
{
    // member function pointer type
    using MemFunPtrType = int(Base::*)(int);
    // to store the member functions pointers
    std::vector<MemFunPtrType> mMemberFunctionPts; 

public:
    Base() // initlize the mMemberFunctionPts once!
        : mMemberFunctionPts{ { &Base::fun1, &Base::fun2 } }
    {}
    virtual int fun1(int inp) = 0;
    virtual int fun2(int inp) = 0;
    virtual ~Base() = default;

    // run choose the correct member function as per the passed index!
    int run(std::size_t index)
    {
        if (2u == mMemberFunctionPts.size() && index == 0)
            return (this->*mMemberFunctionPts[index])(5);
            // or using std::invoke
            // return std::invoke(mMemberFunctionPts[index], this, 5);
        else
            return (this->*mMemberFunctionPts[index])(5);
    }
};

看到一个(Live Demo Here)