关于C++对象继承中的内存布局示例详解
掌握了单继承和多继承的规律,按照总结的一步步分析,就可以最终得到D的虚函数表。 由于子类B继承父类A,所以B与A公用一个虚函数表,又因为B是D多继承中的第一个继承的类,所以B,D共用一个虚函数表。 菱形的虚拟继承(成员变量 + 虚函数覆盖) 参考下面这个例子: class A { public: virtual void func1() { cout << "A::func1()" << endl; } virtual void func2() { cout << "A::func2()" << endl; } public: int _a; }; class B : virtual public A//虚继承A,覆盖func1() { public: virtual void func1() { cout << "B::func1()" << endl; } virtual void func3() { cout << "B::func3()" << endl; } public: int _b; }; class C : virtual public A //虚继承A,覆盖func1() { virtual void func1() { cout << "C::func1()" << endl; } virtual void func3() { cout << "C::func3()" << endl; } public: int _c; }; class D : public B,public C//虚继承B,C,覆盖func1() { virtual void func1() { cout << "D::func1()" << endl; } virtual void func4() { cout << "D::func4()" << endl; } public: int _d; }; typedef void(*FUNC) (); void PrintVTable(int* VTable) { cout << " 虚表地址>" << VTable << endl; for (int i = 0; VTable[i] != 0; ++i) { printf(" 第%d个虚函数地址 :0X%x,VTable[i]); FUNC f = (FUNC)VTable[i]; f(); } cout << endl; } void Test1() { D d; d.B::_a = 1; d.C::_a = 2; d._b = 3; d._c = 4; d._d = 5; cout <<"sizeof(A) = "<< sizeof(A) << endl; cout << "sizeof(B) = " << sizeof(B) << endl; cout << "sizeof(C) = " << sizeof(C) << endl; //打印d的虚函数表 int* VTable = (int*)(*(int*)&d); PrintVTable(VTable); //打印C的虚函数表 VTable = (int*)*(int*)((char*)&d + sizeof(B)-sizeof(A)); PrintVTable(VTable); //打印A的虚函数表 VTable = (int*)*(int*)((char*)&d + sizeof(B)+sizeof(C)-2*sizeof(A)+4); PrintVTable(VTable); } 接下来就慢慢分析: 1)先通过调试查看内存中是如何分配的,并和我们打印出的虚函数表对应起来: 注:由于B,C是虚继承A,所以编译器为了解决菱形继承所带来的“二义性”以及“数据冗余”,便将A放在最末端,并在子类中存放一个虚基表,方便找到父类;而虚基表的前四个字节存放的是对于自己虚函数表的偏移量,再往下四个字节才是对于父类的偏移量。 2)接下来就抽象出来分析模型 总结 1)虚函数按照其声明顺序放于表中; 2)父类的虚函数在子类的虚函数前面(由于子类单继承父类,直接使用父类的虚函数表); 3)覆盖的func()函数被放到了虚表中原来父类虚函数的位置; 4)没有被覆盖的函数依旧; 5)如果B,C虚继承A,并且B,C内部没有再声明或定义虚函数,则B,C没有对应的虚函数表; 6)在菱形的虚拟继承中,要注意A为B,C所共有的,在打印对应虚函数表时要注意偏移量。 好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对编程小技巧的支持。 (编辑:淮北站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |