Virtual Dispatch中的指针数组声明

时间:2014-05-26 07:19:51

标签: c++ arrays function-pointers virtual-functions

我们说我们有三个功能如下:

int fun1()
{
    cout<<"inside fun1"<<endl;
}

int fun2()
{
    cout<<"inside fun2"<<endl;
}

int fun3(int i)
{
    cout<<"inside fun3"<<endl;
}

然后我可以声明用于访问前两个函数的函数的指针数组,如下所示:

int (*p[2])() = {fun1, fun2};

for (int i=0;i<2;++i)
{
    p[i]();
}

我很好奇上面的函数在基类B中被声明为虚拟时的声明和访问机制。有人可以向我解释函数指针如何存储在指针数组中以及如何使用数组调用它们指针。

1 个答案:

答案 0 :(得分:1)

首先要注意的是指向函数的指针和指向成员函数的指针是完全不同的野兽,并且无法在它们之间进行转换。也就是说,您无法将指向virtual的任何成员函数的指针存储到int(*)(),或者更一般地存储为R(*)(Args...)。指向函数的指针只存储要调用的函数的地址。

成员函数需要指向要传递给它们的对象的指针。如果要存储指向成员函数的指针,则需要声明为int (B::*)()(或更一般R(C::*)(Args...))的内容,例如:

#include <iostream>

struct B {
    virtual ~B() {}
    void         non_virtual_fn()      { std::cout << "B::non_virtual_fn\n"; }
    virtual void virtual_fn()          { std::cout << "B::virtual_fn\n"; }
};

struct D: B {
    void         non_virtual_fn()      { std::cout << "D::non_virtual_fn\n"; }
    void         virtual_fn() override { std::cout << "D::virtual_fn\n"; }
};

void (B::*members[])() = {
    &B::non_virtual_fn,
    &B::virtual_fn,
};

template <typename T, int Size>
int size(T (&)[Size]) {
    return Size;
}

int main()
{
    B b;
    D d;
    for (int i(0); i != size(members); ++i) {
        (b.*members[i])();
        (d.*members[i])();
    }
}

编译器实际存储的成员指针的内容未指定。很可能它存储指向非virtual成员函数的成员函数的指针和virtual std::function<Signature>函数的指针。

如果您想根据数组中存储的内容调用成员函数和非成员函数,则需要键入删除部分详细信息,例如使用std::bind()。要调用成员函数,您仍然需要为调用提供一个对象,当然,您可以使用{{1}}或合适的lambda函数来执行此操作。