C++中的多态性和vtable(动态绑定)概念

3

我在思考C++中的多态机制,但有一件事我无法理解。这里有一段非常简单的代码,只有一个类:

#include <iostream>

using namespace std;

class A
{
public:
    int x;
    void fun1();
    double fun2(int, char*);
    void fun3(double, float[]);
};

int main()
{
    cout << sizeof(A) << endl;
return 0;
}

在控制台上会打印出 int 对象(x)的大小 - 这是很明显的。如果我通过添加关键字 virtual 修改我的类,大小将发生变化,因为编译器会添加指向虚函数数组(vtable)的指针。但当我声明完全不同签名的新虚拟方法时,我的类的大小为什么不会改变呢? 我的意思是:

void (*(tab[100]) )(int, double, char*);

这是一个数组的定义,该数组必须包含带有特定签名的函数地址:

void fun(int, double, char*);

只有这种类型的函数才能添加到该数组中,因此无论虚方法类的类型如何,都仅包含一个指向一个虚数组的指针。在我的逻辑中哪里犯了错误?


5
澄清一下:vtable 并不是每个类实例的一部分,它像一个静态成员一样只存在一次。 - Peter - Reinstate Monica
2个回答

2
它可能是有用的

虚拟表格实际上相当简单,尽管用语言描述有些复杂。首先,每个使用虚拟函数(或派生自使用虚拟函数的类)的类都被赋予自己的虚拟表格。这个表格只是编译器在编译时设置的静态数组。虚拟表格包含每个可以被该类的对象调用的虚拟函数的一个条目。这个表格中的每个条目只是一个指向该类可访问的最终派生函数的函数指针。


1

首先,标准并没有对虚表(virtual tables)做出任何规定,它只讨论了虚函数和多态性。每个编译器都可以以任何喜欢的方式实现这个特性。

虚表只是虚函数的一种常见实现方式,它不是必须的,并且在每个编译器中的实现都不同。

最后,在我的Visual Studio 2015中,下面这段代码:

class A1 {
    int x;
    void doIT(){}
};

class A2 {
    int x;
    virtual void doIT(){}
};

constexpr int size = sizeof(A1);
constexpr int size2 = sizeof(A2);

使size为4字节,但size2为12字节,这打破了您的假设。
同样,GCC、Clang甚至C++/CLI可能会有不同的行为,并产生不同的大小。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接