C ++:虚拟指针的原型

时间:2012-06-03 17:38:47

标签: c++ inheritance virtual vtable vptr

我不确定这是否记录在任何地方。 我们都知道在虚函数的情况下,每个类都有一个vptr,它指向一个称为虚拟表的函数指针数组。 我想知道vptr的原型是什么。 例如,如果一个类声明如下,

class A
{
   int a;
   public: A(){}
   virtual void display();
   virtual void setValue(int x);
};

现在我们在A类的vtable中有两个函数指针。一个vptr如何能够对不同原型的两个定义?

如果我的理解错误,请告诉我。

THX! 拉胡

3 个答案:

答案 0 :(得分:3)

vptr是一个实现细节,因此它没有原型。

答案 1 :(得分:1)

正如Oli Charlesworth指出的那样,虚拟指针是一个实现细节,所以这个问题在C ++方面确实没有意义。也就是说,以下手动实现(某些功能)虚拟功能可能有助于您理解:

struct vtable {
    void (*display)(void*);
    void (*setValue)(void*, int);
};

void A_display(void *this_) { /*Cast this_ to A* and do A stuff*/ }
void A_setValue(void *this_, int x) { /*Cast this_ to A* and do A stuff*/ }

vtable A_vtable = {A_display, A_setValue};

struct A {
    vtable *vptr = &A_vtable;
    int a;
    public: A(){}
};

void B_display(void *this_) { /*Cast this_ to B* and do B stuff*/ }
void B_setValue(void *this_, int x) { /*Cast this_ to B* and do B stuff*/ }

vtable B_vtable = {B_display, B_setValue};

struct B {
    vtable *vptr = &B_vtable;
    int a;
    public: B(){}
};

void display(void *obj) {
    ((*static_cast<vtable**>(obj))->display)(obj);
}
void setValue(void *obj, int) {
    ((*static_cast<vtable**>(obj))->setValue)(obj, int);
}

当然,这只提供了虚函数功能的一小部分,但是看到vptrs指向具有固定类型的函数指针集合应该相当简单。

答案 2 :(得分:1)

虚拟表(在使用这种东西的实现中)是“编译魔术”的产物。它不需要具有特定的原型,因为没有C ++代码直接使用它。相反,编译器自定义生成一个符合每个需要一个类的类。编译器还生成访问每个元素的代码,因此它可以保证以类型安全的方式访问每个元素。

例如,编译器知道A::setValue方法的槽持有一个指向与setValue签名匹配的函数的指针,因为编译器是首先将它放在那里的编译器。此外,直接访问该槽的唯一代码是编译器生成的机器代码,并且在生成此类代码之前,编译器已经确认原始C ++代码正在调用setValue函数。因此,不用担心setValue槽可以容纳除setValue - 符合函数指针之外的任何东西。也不担心可能会访问其他一些插槽;如果发生这种情况,那将是一个编译器错误,绝不会因普通用户代码而发生。

表的元素永远不会被视为一个组,因此不要求它们都具有相同的类型。最多,它们都有一种“适合CPU跳转到的通用指针或偏移量”。因为那时它不是真正的C ++,所以“类型”不必适合任何特定的C ++类型。