C++虚继承中的对象内存布局
2016-03-09 20:17
405 查看
钻石型虚拟继承
虚继承是为了解决多继承中的数据冗余而出现的。
eg:
对象在内存中的布局:
大家可以发现:
0x0014F8F8 + 0xFFFFFFFC(-4) = 0x0014F8F4, 0x0014F8F8 + 0x00000018 = 0x0014F910;
0x0014F904 + 0xFFFFFFFC(-4) = 0x0014F900, 0x0014F904 + 0x0000000c = 0x0014F910.
所以,有以下结论:
在虚继承时,类中会自动加一个指针(VBPTR),该变量指向一个全类共享的偏移量表,如果本类有虚函数,那么第一项记录着当前子对象相对与虚基类表指针(VBPTR指针)的偏移,是FF FF FF FC(也就是-4),如果没有则是零;第二项起是被继承的基类(上述例子为Base类)子对象相对于VBPTR指针的偏移量。
虚继承是为了解决多继承中的数据冗余而出现的。
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; }程序运行结果:
对象在内存中的布局:
大家可以发现:
0x0014F8F8 + 0xFFFFFFFC(-4) = 0x0014F8F4, 0x0014F8F8 + 0x00000018 = 0x0014F910;
0x0014F904 + 0xFFFFFFFC(-4) = 0x0014F900, 0x0014F904 + 0x0000000c = 0x0014F910.
所以,有以下结论:
在虚继承时,类中会自动加一个指针(VBPTR),该变量指向一个全类共享的偏移量表,如果本类有虚函数,那么第一项记录着当前子对象相对与虚基类表指针(VBPTR指针)的偏移,是FF FF FF FC(也就是-4),如果没有则是零;第二项起是被继承的基类(上述例子为Base类)子对象相对于VBPTR指针的偏移量。
相关文章推荐
- 关于指针的一些事情
- C# Pointer指针应用实例简述
- C++智能指针实例详解
- C++指向函数的指针实例解析
- 关于c语言指针的两处小tip分享
- 浅析iterator与指针的区别
- 探讨C++中数组名与指针的用法比较分析
- C++编程指向成员的指针以及this指针的基本使用指南
- 详解C++中的指针、数组指针与函数指针
- C++中字符串以及数组和指针的互相使用讲解
- C语言安全之数组长度与指针实例解析
- C++中指向对象的常指针与指向常对象的指针详解
- 指向变量的常指针与指向常变量的指针详细解析
- C#通过指针实现快速拷贝的方法
- php中将指针移动到数据集初始位置的实现代码[mysql_data_seek]
- C#通过指针读取文件的方法
- C语言指针学习经验总结浅谈
- C++交换指针实例
- C/C++中指针和引用之相关问题深入研究
- 讲解C语言编程中指针赋值的入门实例