关于虚函数表,可见博客 传送 ,但是要注意,一般被继承的第一个基类的虚函数表合并至子类的虚函数表,(基类的虚函数在前,除非有虚函数覆盖,子类的虚函数在后)
主要讲了在无虚继承情况下各种情况的虚函数表的情况,
因此,就牵扯到了类的大小的问题:
1)对于一个空类,sizeof=1;
2)静态成员不属于类大小中,且成员函数也不属于类大小中
3)类与继承情况下类的大小:
情况一: 无虚函数继承,但有虚函数的情况
class A { public: char a[3]; virtual void fa() {}; }; class B : public A { public: char b[3]; virtual void fa() {}; }; class C : public A { public: char c[3]; virtual void bb() {}; }; int main() { cout << sizeof(A) << endl; cout << sizeof(B) << endl; cout << sizeof(C) << endl; }
结果是:VS2015 debug x86
sizeof(A) = 8
= A的虚函数表指针的4字节+char对齐的4字节
sizeof(B) = 12
= B的虚函数表指针的4字节 + 类B中char对齐的4字节+类A中char对齐的4字节
sizeof(C) = 12
= C的虚函数表指针的4字节 + 类C中char对齐的4字节+类A中char对齐的4字节
情况二: 虚函数继承,有虚函数的情况
class A { public: char a[3]; virtual void fa() {}; }; class B : virtual public A { public: char b[3]; virtual void fa() {}; //虚函数覆盖 }; class C : virtual public A { public: char c[3]; virtual void bb() {}; //无虚函数覆盖 }; class D :public B, public C { public: char d[3]; }; int main() { cout << sizeof(A) << endl; cout << sizeof(B) << endl; cout << sizeof(C) << endl; cout << sizeof(D) << endl; }
虚继承:虚继承的提出是为了解决多重继承时,可能会保存两份副本的问题,也就是说用了虚继承就只保留了一份副本,但是这个副本是被多重继承的基类所共享的。
虚继承底层实现原理与编译器相关,一般通过虚基类指针和虚基类表实现,每个虚继承的子类都有一个虚基类指针(占用一个指针的存储空间,4字节)和虚基类表(不占用类对象的存储空间)(需要强调的是,虚基类依旧会在子类里面存在拷贝,只是仅仅最多存在一份而已,并不是不在子类里面了);当虚继承的子类被当做父类继承时,虚基类指针也会被继承。
因此 :要考虑虚函数表指针和虚基类指针
结果是:VS2015 debug x86
sizeof(A) = 8
= A的虚函数表指针的4字节+char对齐的4字节
sizeof(B) = 16
= B的虚函数表指针的4字节(合并类A覆盖的虚函数) +A的虚基类指针4字节+类B中char对齐的4字节 + 类A中char对齐的4字节
sizeof(C) = 20
= C的虚函数表指针的4字节(合并类A覆盖的虚函数) +A的虚基类指针4字节+类C中char对齐的4字节 +类A的虚函数表指针(没覆盖的虚函数)+ 类A中char对齐的4字节
sizeof(D) = 32
= 类D的虚函数表指针的4字节(和类B的虚函数表合并) +类D中char对齐的4字节 +类B中的虚基类指针4字节+类B中char对齐的4字节+类C中的虚基类指针4字节+类C虚函数表指针4字节+类C中char对齐的4字节+ 共享类A中char对齐的4字节