钻石型虚拟继承
ios
虚继承是为了解决多继承中的数据冗余而出现的。
ide
eg:函数
#define _CRT_SECURE_NO_WARNINGS 1 #include <iostream> using namespace std; typedef void(*FUNC)(); class Base { public: virtual void fun1() { cout << "Base::fun1()" << endl; } public: int _b; }; class Parent1:virtual public Base { public: virtual void fun1() { cout << "Parent1::fun1()" << endl; } virtual void fun2() { cout << "Parent1::fun2()" << endl; } public: int _p1; }; class Parent2 :virtual public Base { public: virtual void fun1() { cout << "Parent2::fun1()" << endl; } virtual void fun3() { cout << "Parent2::fun3()" << endl; } public: int _p2; }; class Child : public Parent1,public Parent2 { public: virtual void fun1() { cout << "Child::fun1()" << endl; } virtual void fun2() { cout << "Child::fun2()" << endl; } virtual void fun3() { cout << "Child::fun3()" << endl; } virtual void fun4() { cout << "Child::fun4()" << endl; } public: int _c; }; void PrintVfptr(int* vptr) //打印虚函数表 { cout << "虚函数表: " << vptr << endl; for (int i = 0; vptr[i] != 0; ++i) { printf("第%d个虚函数:%p >> ", i, vptr[i]); FUNC f = (FUNC)(vptr[i]); f(); } } void PrintfMove(int* vbptr) //打印偏移量 { cout << "偏移量 >: " << endl; for (int i = 0; vbptr[i] != 0; ++i) { printf("第%d个虚函数:%d\n", i, vbptr[i]); } cout << endl; } void Test() { Child c; c._b = 1; c._p1 = 2; c._p2 = 3; c._c = 4; cout << "sizeof(Base)::" << sizeof(Base) << endl; cout << "sizeof(Parent1)::" << sizeof(Parent1) << endl; cout << "sizeof(Parent2)::" << sizeof(Parent2) << endl; cout << "sizeof(Child)::" << sizeof(Child) << endl; int* cAddress = (int*)&c; cout << "Parent1::"; int* tmpP1 = (int*)(*cAddress); PrintVfptr(tmpP1); cout << "Parent1::"; int* moveP1 = (int*)(*(cAddress + 1)); PrintfMove(moveP1); cout << endl; cout << "Parent2::"; int* tmpP2 = (int*)(*(cAddress + 3)); PrintVfptr(tmpP2); cout << endl; cout << "Parent1::"; int* moveP2 = (int*)(*(cAddress + 4)); PrintfMove(moveP2); cout << endl; int* tmpBase = (int*)(*(cAddress + 7)); PrintVfptr(tmpBase); cout << endl; } int main() { Test(); system("pause"); return 0; }
程序运行结果:布局
对象在内存中的布局:spa
0x0014F8F8 + 0xFFFFFFFC(-4) = 0x0014F8F4, 0x0014F8F8 + 0x00000018 = 0x0014F910; 对象
0x0014F904 + 0xFFFFFFFC(-4) = 0x0014F900, 0x0014F904 + 0x0000000c = 0x0014F910.blog
因此,有如下结论:继承
在虚继承时,类中会自动加一个指针(VBPTR),该变量指向一个全类共享的偏移量表,若是本类有虚函数,那么第一项记录着当前子对象相对与虚基类表指针(VBPTR指针)的偏移,是FF FF FF FC(也就是-4),若是没有则是零;第二项起是被继承的基类(上述例子为Base类)子对象相对于VBPTR指针的偏移量。内存