虚继承
虚继承用于解决多继承条件下的菱形继承问题(浪费存储空间、存在二义性)。
底层实现原理与编译器相关,一般通过虚基类指针和虚基类表实现,每个虚继承的子类都有一个虚基类指针(占用一个指针的存储空间,4字节)和虚基类表(不占用类对象的存储空间)(需要强调的是,虚基类依旧会在子类里面存在拷贝,只是仅仅最多存在一份而已,并不是不在子类里面了);当虚继承的子类被当做父类继承时,虚基类指针也会被继承。
实际上,vbptr 指的是虚基类表指针(virtual base table pointer),该指针指向了一个虚基类表(virtual table),虚表中记录了虚基类与本类的偏移地址;通过偏移地址,这样就找到了虚基类成员,而虚继承也不用像普通多继承那样维持着公共基类(虚基类)的两份同样的拷贝,节省了存储空间。
1 #include<iostream> 2 using namespace std; 3 4 class A //大小为4 5 { 6 public: 7 int a; 8 double b; 9 }; 10 //在32位环境下,大小为12,变量a,b共8字节,虚基类表指针4; 11 //在64位环境下,变量a 4个字节,b 4个字节,虚基类表指针8个字节,为了对齐,大小总共24 12 class B :virtual public A 13 { 14 public: 15 int b; 16 }; 17 18 //与B一样 19 class C :virtual public A 20 { 21 public: 22 int c; 23 }; 24 25 //在32位环境下,大小为24,变量a,b,c,d共16,B的虚基类指针4,C的虚基类指针 26 class D :public B, public C 27 { 28 public: 29 int d; 30 }; 31 32 int main() 33 { 34 cout << sizeof(A) << endl; 35 cout << sizeof(B) << endl; 36 cout << sizeof(C) << endl; 37 cout << sizeof(D) << endl; 38 cout << sizeof(void *) << endl; 39 40 system("pause"); 41 return 0; 42 }