这篇文章是在默认读者已经简单了解什么是虚函数,即看到一段代码可以快速判断出哪个是虚函数,以及虚函数的基本性质的前提下。
一、虚函数表指针与虚函数表
一个空类,使用sizeof计算大小,得 1 ;如果向类中添加两个空的成员函数,再次使用sizeof计算类的大小,还是 1 。这说明:类的普通成员函数并不占用类对象的内存空间。
总结来讲:只有非静态成员变量属于类的对象上(即影响类的大小),其余“静态成员变量”,“非静态成员函数”,“静态成员函数”等均不属于类对象上。
如果向类中添加一个或多个虚函数,类的大小会变为 4 ,这个大小就是虚函数表指针的大小。当一个或者多个虚函数加入一个类中之后,编译器会向类中插入一个看不见的成员变量,在类中,这个看不见的成员对象就是虚函数表指针(vptr),而虚函数表指针(vtbl)占用了内存空间。
当类中至少存在一个虚函数时,编译器在编译期间会为虚函数生成一个虚函数表。
二、虚函数、虚函数表、虚函数表指针的关系
对于有虚函数的类A,在编译期间,编译器会在类A的构造函数中安插为虚函数表指针赋值的语句。因此当创建一个类A对象的时候,会执行A的构造函数,因为A中有给虚函数表指针赋值的语句,所以就能使虚函数表指针指向类A中的虚函数表。
三、举例
假设有一个类A,它的对象如下:
class A {
public:
void func1();
void func2();
public:
virtual void vfunc() {};
virtual void vfunc2() {};
virtual ~A() {};
private:
int m_a;
int m_b;
};
这时候用sizeof计算A的大小,结果为12,为什么呢?
A总共有三部分:一个虚函数表指针和两个普通成员变量。A中有虚函数,所以会自动创建一个虚函数表指针来指向A中的虚函数表,虚函数表中包含三个虚函数。虚函数表指针占4个字节的大小;两个成员变量各占4个字节,所以共12字节。
图示如下: