C++对象模型
来源:互联网 发布:美橙域名管理地址 编辑:程序博客网 时间:2024/06/06 09:53
1、简单模型
1.1、概述
C++类中有两种数据成员:static、nonstatic;三种成员函数:static、nonstatic、virtual。它们在内存中的布局方式和访问方式是不同的。像nonstatic对象是在类对象内存储,虚函数是通过一个虚表指针指向一个虚表再通过虚表查找。静态和非静态函数都在对象之外存储。
1.2、对象模型图例
定义一个C++类:
class Base{public: Base(int); virtual ~Base(void); virtual void base_print() const; static void baseStaticFunc(); void baseNonStaticFunc();protected: int iBase; static int iSatic;};
Base类中各种成员如下图方式存储、访问:
不同编译存储各个成员可能有所差异,这是在Windows+VS2012中的布局。
可以看出Base对象中第一项是虚表指针,这个指针指向一张虚表,虚表中存储的是Base类各个虚函数的存储地址。在紧邻虚表的前一个位置是一个typeinfoPtr指针,它指向的是Base类的type_info信息。Base类的静态和非静态成员函数,静态成员数据在Base对象外存储。
1.3、验证模型
以下代码验证1.2图中模型:
void Base_Model(){ cout << "********************Base b Model********************" << endl; Base b(3); cout << "对象b的内存地址 &b = " << &b << endl; cout << "对象b中第一项 _vptr Base 虚表指针的值也即虚表首地址 = " << hex << *(int*)(&b) << endl; cout << "对象b中第二项 int Base::iBase的值 = " << hex << *((int*)(&b) + 1) << endl; cout << "虚函数表中第一个slot的值也即虚函数Base::~Base()的入口地址 = " << hex << *(int*)(*(int*)(&b)) << endl; cout << "虚函数表中第二个slot的值也即虚函数Base::base_print()的入口地址 = " << hex << *((int*)(*(int*)(&b)) + 1) << endl; pFun pBasePrint = (pFun)(*((int*)(*(int*)(&b)) + 1)); pBasePrint(); //注意这里输出是不一样的,这个调用仅仅是调用那段代码但是里面的iBase值不确定,因为iBase在Base对象中 b.base_print(); cout << "typeinfoPtr指针的存储位置 = " << ((*(int*)(&b)) - 1) << endl; cout << "typeinfoPtr指针的值也即Base's type_info的首地址 = " << hex << *((int*)(*(int*)(&b)) - 1) << endl;// cout << hex << Base::baseStaticFunc << endl;// cout << hex << Base::baseStaticFunc2 << endl;// cout << hex << &Base::baseNonStaticFunc << endl;// typedef void (Base::*pmf)();// pmf pt = &Base::baseNonStaticFunc;// cout << hex << pt << endl;}
运行结果:
2、对象模型with单继承
2.1、无重写单继承
无重写指的是派生类没有重写基类的虚函数。定义一个Base的派生类(除析构函数外无重写):
class Derived : public Base{public: Derived(int); virtual ~Derived(void); virtual void derived_print(void);protected: int iDerived;};
则派生类Derived及对象的布局方式如下图:
可以看到父类的虚函数放在了虚函数表的前面,后面放的是子类新加入的虚函数,子类的虚析构函数覆盖了父类的虚析构函数。
验证模型:
void DerivedInheritBase(){ cout << "********************Derived d Model********************" << endl; Derived d(6); cout << "对象d的内存地址 &d = " << &d << endl; cout << "对象d中第一项 _vptr Derived 虚表指针的值也即虚表首地址 = " << hex << *(int*)(&d) << endl; cout << "对象d中第二项 int Base::iBase的值 = " << hex << *((int*)(&d) + 1) << endl; cout << "对象d中第三项 int Derived::iDerived的值 = " << hex << *((int*)(&d) + 2) << endl; cout << "虚函数表中第一个slot的值也即虚函数Derived::~Derived()的入口地址 = " << hex << *(int*)(*(int*)(&d)) << endl; cout << "虚函数表中第二个slot的值也即虚函数Base::base_print()的入口地址 = " << hex << *((int*)(*(int*)(&d)) + 1) << endl; cout << "虚函数表中第二个slot的值也即虚函数Derived::derived_print()的入口地址 = " << hex << *((int*)(*(int*)(&d)) + 2) << endl; pFun pBasePrint = (pFun)(*((int*)(*(int*)(&d)) + 1)); pBasePrint(); d.base_print(); pFun pDerivdPrint = (pFun)(*((int*)(*(int*)(&d)) + 2)); pDerivdPrint(); d.derived_print(); cout << "typeinfoPtr指针的存储位置 = " << ((*(int*)(&d)) - 1) << endl; cout << "typeinfoPtr指针的值也即Derived's type_info的首地址 = " << hex << *((int*)(*(int*)(&d)) - 1) << endl;}
运行结果:
2.2、有重写单继承
有重写指的是派生类重写了基类的虚函数。定义一个Base的派生类带有重写(非析构函数):
class DerivedWithOverride : public Base{public: DerivedWithOverride(int i); virtual ~DerivedWithOverride(void); virtual void derivedWithOverride_print() const; virtual void base_print() const;protected: int iDWO;};
则派生类DerivedWithOverride及对象的布局方式如下图:
可以看出子类重写了父类的base_print()函数。
验证模型:
void DerivedOverrideInheritBase(){ cout << "********************DerivedWithOverride dow Model********************" << endl; DerivedWithOverride dow(9); cout << "对象dow的内存地址 &dow = " << &dow << endl; cout << "对象dow中第一项 _vptr DerivedWithOverride 虚表指针的值也即虚表首地址 = " << hex << *(int*)(&dow) << endl; cout << "对象dow中第二项 int Base::iBase的值 = " << hex << *((int*)(&dow) + 1) << endl; cout << "对象dow中第三项 int DerivedWithOverride::iDWO的值 = " << hex << *((int*)(&dow) + 2) << endl; cout << "虚函数表中第一个slot的值也即虚函数DerivedWithOverride::~DerivedWithOverride()的入口地址 = " << hex << *(int*)(*(int*)(&dow)) << endl; cout << "虚函数表中第二个slot的值也即虚函数DerivedWithOverride::base_print()的入口地址 = " << hex << *((int*)(*(int*)(&dow)) + 1) << endl; cout << "虚函数表中第三个slot的值也即虚函数DerivedWithOverride::DerivedWithOverride()的入口地址 = " << hex << *((int*)(*(int*)(&dow)) + 2) << endl; pFun pBasePrint = (pFun)(*((int*)(*(int*)(&dow)) + 1)); pBasePrint(); dow.base_print(); pFun pDerivdPrint = (pFun)(*((int*)(*(int*)(&dow)) + 2)); pDerivdPrint(); dow.derivedWithOverride_print(); cout << "typeinfoPtr指针的存储位置 = " << ((*(int*)(&dow)) - 1) << endl; cout << "typeinfoPtr指针的值也即DerivedWithOverride's type_info的首地址 = " << hex << *((int*)(*(int*)(&dow)) - 1) << endl;}
运行结果:
2.3、虚继承
虚基类是为了解决多重继承中多个间接父类的情况,因此不能使用以上的方法。虚继承的派生类和普通继承派生类的内存结构有很大差异,虚继承的子类有自己的虚函数表,同时也保存了父类的虚函数表,子类数据和父类数据中间用一个分隔符作为分界线。(若派生类没有自己的虚函数,那么派生类就没有虚函数表)
定义一个派生类虚继承自Base类:
class DerivedVirtual_1 : virtual public Base{public: DerivedVirtual_1(int i); virtual ~DerivedVirtual_1(void); virtual void base_print() const; virtual void derivedVirtual_1_print() const;protected: int iDV_1;};
则派生类DerivedVirtual_1 及对象的布局方式如下图:
可以看到,子类的虚函数表指针及数据成员在基类的前面,子类父类之间用分隔符0隔开,子类重写的父类虚函数放在父类虚函数表中。
验证模型:
void DerivedVirtualInheritBase(){ cout << "********************DerivedVirtual_1 dv1 Model********************" << endl; DerivedVirtual_1 dv1(12); cout << "对象dv1的内存地址 &dow = " << &dv1 << endl; cout << "对象dv1中第一项 _vptr DerivedVirtual_1 虚表指针的值也即子类虚表首地址 = " << hex << *(int*)(&dv1) << endl; cout << "对象dv1中第二项 Ptr 所指内存中的值 = " << dec << *(int*)(*((int*)(&dv1) + 1)) << endl; cout << "对象dv1中第三项 int DerivedVirtual_1::iDV_1的值 = " << dec << *((int*)(&dv1) + 2) << endl; cout << "对象dv1中第四项 分隔符 0 的值 = " << dec << *((int*)(&dv1) + 3) << endl; cout << "子类虚函数表中第一个slot的值也即虚函数DerivedVirtual_1::derivedVirtual_1_print()的入口地址 = " << hex << *(int*)(*(int*)(&dv1)) << endl; pFun pDerivedVirtual1Print = (pFun)(*(int*)(*(int*)(&dv1))); pDerivedVirtual1Print(); dv1.derivedVirtual_1_print(); cout << "子类typeinfoPtr指针的存储位置 = " << (*(int*)(&dv1) - 1) << endl; cout << "子类typeinfoPtr指针的值也即DerivedVirtual_1's type_info的首地址 = " << hex << *((int*)(*(int*)(&dv1) - 1)) << endl; cout << "对象dv1中第五项 _vptr Base 虚表指针的值也即父类虚表首地址 = " << hex << *((int*)(&dv1) + 4) << endl; cout << "对象dv1中第六项 int Base::iBase 的值 = " << dec << *((int*)(&dv1) + 5) << endl; cout << "父类虚函数表中第一个slot的值也即虚函数DerivedVirtual_1::~DerivedVirtual_1()的入口地址 = " << hex << *(int*)(*((int*)(&dv1) + 4)) << endl; cout << "父类虚函数表中第二个slot的值也即虚函数DerivedVirtual_1::base_print()的入口地址 = " << hex << *((int*)(*((int*)(&dv1) + 4)) + 1) << endl; pFun pBasePrint = (pFun)(*((int*)(*((int*)(&dv1) + 4)) + 1)); pBasePrint(); dv1.base_print();}
运行结果:
特例:
(1)Base的派生类DerivedVirtual_1既没有自己的虚函数也没有自己的成员数据,则DerivedVirtual_1的内存布局:
测试代码如下:
void DerivedVirtualInheritBase_noNewData() { cout << "********************DeriveDVirtual_1_noData dv1n Model********************" << endl; DeriveDVirtual_1_noData dv1n; cout << "分隔符的值 = " << dec << *(int*)(*((int*)(&dv1n))) << endl; cout << "父类虚函数表中第二个slot的值也即虚函数Base::base_print()的入口地址 = " << dec << *((int*)(*((int*)(&dv1n) + 1)) + 1) << endl; pFun pBasePrint = (pFun)(*((int*)(*((int*)(&dv1n) + 1)) + 1)); pBasePrint(); dv1n.base_print();}
(2)Base的派生类DerivedVirtual_1有自己的虚函数,没有自己的成员数据,则DerivedVirtual_1的内存布局:
测试代码如下:
//虚继承中子类有自己的虚函数,没有新的成员数据void DerivedVirtualInheritBase_noNewData(){ cout << "********************DeriveDVirtual_1_noData dv1n Model********************" << endl; DeriveDVirtual_1_noData dv1n; cout << "子类虚函数表中第一个slot的值也即虚函数DeriveDVirtual_1_noData::deriveDVirtual_1_noData_print()的入口地址 = " << hex << *(int*)(*(int*)(&dv1n)) << endl; pFun pDerivedVirtual1Print = (pFun)(*(int*)(*(int*)(&dv1n))); pDerivedVirtual1Print(); dv1n.deriveDVirtual_1_noData_print(); cout << "ptr 所执行的值 = " << dec << *(int*)(*((int*)(&dv1n) + 1)) << endl; //cout << "分隔符的值 = " << dec << *((int*)(&dv1n) + 2) << endl; //派生类没有数据就不需要分隔符了 cout << "父类虚函数表中第二个slot的值也即虚函数Base::base_print()的入口地址 = " << dec << *((int*)(*((int*)(&dv1n) + 2)) + 1) << endl; pFun pBasePrint = (pFun)(*((int*)(*((int*)(&dv1n) + 2)) + 1)); pBasePrint(); dv1n.base_print();}
(3)Base的派生类DerivedVirtual_1没有自己的虚函数,有自己的成员数据,则DerivedVirtual_1的内存布局:(对这个不甚理解,但是Windows下在VS2012验证确实是这样!)
测试代码如下:
//虚继承中子类没有自己的虚函数,有新的成员数据void DerivedVirtualInheritBase_noNewData(){ cout << "********************DeriveDVirtual_1_noData dv1n Model********************" << endl; DeriveDVirtual_1_noData dv1n; cout << *(int*)(*(int*)(&dv1n)) << endl; cout << "iDV_1的值 = " << dec << *((int*)(&dv1n) + 1) << endl; cout << "父类虚函数表中第二个slot的值也即虚函数Base::base_print()的入口地址 = " << hex << *((int*)(*((int*)(&dv1n) + 2)) + 1) << endl; pFun pBasePrint = (pFun)(*((int*)(*((int*)(&dv1n) + 2)) + 1)); pBasePrint(); dv1n.base_print(); cout << "Base::iBase值 = " << dec << *((int*)(&dv1n) + 3) << endl; }
3、对象模型with多继承
再定义一个基类:
class Base_2{public: Base_2(int i); virtual ~Base_2(void); virtual void base_print() const;protected: int iBase_2;};
定义一个派生类继承自Base, Base_2
class DerivedMulti : public Base, public Base_2{public: DerivedMulti(int i); virtual ~DerivedMulti(void); virtual void base_print() const; //重写父类的print virtual void derivedMulti_print() const; //自己的printprotected: int iDM;};
则派生类DerivedMulti 及对象的布局方式如下图:
可以看出DerivedMulti对象中先放第一个基类Base的虚表指针和数据然后是第二个基类的虚表指针和数据,最后是子类的成员数据。子类的虚函数放在了第一个基类的虚表中,放在基类虚函数后面。基类在DerivedMulti对象中的存放顺序是按照声明时public Base, public Base_2顺序决定的。
模型验证:
void DerivedMultiInheritBases(){ cout << "********************DeriveDVirtual_1_noData dv1n Model********************" << endl; DerivedMulti dm(18); cout << "对象dm的内存地址 &dm = " << &dm << endl; cout << "对象dm中第一项 _vptr Base 虚表指针的值也即第一个基类虚表首地址 = " << hex << *(int*)(&dm) << endl; cout << "对象dm中第二项 int Base::iBase值 = " << dec << *((int*)(&dm) + 1) << endl; cout << "对象dm中第三项 _vptr Base_2 虚表指针的值也即第二个基类虚表首地址 = " << hex << *((int*)(&dm) + 2) << endl; cout << "对象dm中第四项 int Base_2::iBase_2值 = " << dec << *((int*)(&dm) + 3) << endl; cout << "对象dm中第四项 int DerivedMulti::iDM值 = " << dec << *((int*)(&dm) + 4) << endl; cout << "第一个基类Base的typeinfoPtr指针的存储位置 = " << hex << (*(int*)(&dm) - 1) << endl; cout << "第一个基类Base的typeinfoPtr指针的值也即Base's type_info的首地址 = " << hex << *((int*)(*(int*)(&dm) - 1)) << endl; cout << "第一个基类Base的虚函数表中第一个slot的值也即虚函数DerivedMulti::~DerivedMulti()的入口地址 = " << hex << *(int*)(*(int*)(&dm)) << endl; cout << "第一个基类Base的虚函数表中第二个slot的值也即虚函数DerivedMulti::base_print()的入口地址 = " << hex << *((int*)(*(int*)(&dm))+1) << endl; pFun pDerivedMultiBasePrint = (pFun)(*((int*)(*(int*)(&dm)) + 1)); pDerivedMultiBasePrint(); dm.base_print(); cout << "第一个基类Base的虚函数表中第三个slot的值也即虚函数DerivedMulti::derivedMulti_print()的入口地址 = " << hex << *((int*)(*(int*)(&dm))+2) << endl; pFun pDerivedMultiPrint = (pFun)(*((int*)(*(int*)(&dm)) + 2)); pDerivedMultiPrint(); dm.derivedMulti_print(); cout << "第二个基类Base_2的typeinfoPtr指针的存储位置 = " << hex << (*((int*)(&dm) + 2) - 1) << endl; cout << "第二个基类Base_2的typeinfoPtr指针的值也即Base_2's type_info的首地址 = " << hex << *((int*)(*((int*)(&dm) + 2) - 1)) << endl; cout << "第二个基类Base_2的虚函数表中第一个slot的值也即虚函数DerivedMulti::~DerivedMulti()的入口地址 = " << hex << *(int*)(*((int*)(&dm) + 2)) << endl; cout << "第二个基类Base_2的虚函数表中第二个slot的值也即虚函数DerivedMulti::base_print()的入口地址 = " << hex << *((int*)(*((int*)(&dm) + 2))+1) << endl; pFun pDerivedMultiBase2Print = (pFun)(*((int*)(*((int*)(&dm) + 2))+1)); pDerivedMultiBase2Print(); dm.base_print();}
运行结果:
4、钻石型继承关系
DerivedVirtual_2类:
class DerivedVirtual_2 : virtual public Base{public: DerivedVirtual_2(int i); virtual ~DerivedVirtual_2(void); virtual void base_print() const; virtual void derivedVirtual_2_print() const;protected: int iDV_2;};
DeriveDVirtualDiamond类:
class DerivdeVirtualDiamond : public DerivedVirtual_1, public DerivedVirtual_2{public: DerivdeVirtualDiamond(int i); virtual ~DerivdeVirtualDiamond(void); virtual void base_print() const; virtual void derivedVirtual_1_print() const; virtual void derivedVirtualDiamond_print() const;protected: int iDVD;};
DeriveDVirtualDiamond类及对象内存布局方式:
如图所示先存放直接父基类DerivedVirtual_1的数据(先声明),然后是DerivedVirtual_2,再是DerivedVirtualDiamond本身的,然后使用分隔符0分割最后存放虚基类的。注意,DerivedDiamod::~DerivedVirtualDiamond(), DerivedDiamod::base_print()放在_vptr Base的虚表中。
验证模型:
void DerivedVirtualDiamondInherit(){ cout << "********************DerivedVirtualDiamond dvd Model********************" << endl; DerivdeVirtualDiamond dvd(21); cout << "对象dvd的内存地址 &dm = " << &dvd << endl; cout << "对象dvd中第一项 _vptr DerivedVirtual_1 虚表指针的值也即DerivedVirtual_1虚表首地址 = " << hex << *(int*)(&dvd) << endl; cout << "对象dvd中第二项 Ptr所指内存中的值 = " << dec << *(int*)(*((int*)(&dvd) + 1)) << endl; cout << "对象dvd中第三项 int DerivedVirtual_1::iDV_1的值 = " << dec << *((int*)(&dvd) + 2) << endl; cout << "对象dvd中第四项 _vptr DerivedVirtual_2 虚表指针的值也即DerivedVirtual_2虚表首地址 = " << hex << *((int*)(&dvd) +3)<< endl; cout << "对象dvd中第五项 Ptr所指内存中的值 = " << dec << *(int*)(*((int*)(&dvd) + 4)) << endl; cout << "对象dvd中第六项 int DerivedVirtual_2::iDV_2的值 = " << dec << *((int*)(&dvd) + 5) << endl; cout << "对象dvd中第七项 int DerivdeVirtualDiamond::iDVD的值 = " << dec << *((int*)(&dvd) + 6) << endl; cout << "对象dvd中第八项分隔符 0 的值 = " << dec << *((int*)(&dvd) + 7) << endl; cout << "对象dvd中第九项 _vptr Base 虚表指针的值也即Base虚表首地址 = " << hex << *((int*)(&dvd) + 8)<< endl; cout << "对象dvd中第十项 int Base::iBasee的值 = " << dec << *((int*)(&dvd) + 9)<< endl; cout << "基类DerivedVirtual_1的typeinfoPtr指针的存储位置 = " << hex << (*(int*)(&dvd) - 1) << endl; cout << "基类DerivedVirtual_1的typeinfoPtr指针的值也即DerivedVirtual_1's type_info的首地址 = " << hex << *((int*)(*(int*)(&dvd) - 1)) << endl; cout << "基类DerivedVirtual_1的虚函数表中第一个slot的值也即虚函数DerivdeVirtualDiamond::derivedVirtual_1_print()的入口地址 = " << hex << *(int*)(*(int*)(&dvd)) << endl; pFun pDerivedMultiVirtual1Print = (pFun)(*((int*)(*(int*)(&dvd)))); pDerivedMultiVirtual1Print(); dvd.derivedVirtual_1_print(); cout << "基类DerivedVirtual_1的虚函数表中第二个slot的值也即虚函数DerivdeVirtualDiamond::derivedVirtualDiamond_print()的入口地址 = " << hex << *((int*)(*(int*)(&dvd))+1) << endl; pFun pDerivedMultiDiamondPrint = (pFun)(*((int*)(*(int*)(&dvd)) + 1)); pDerivedMultiDiamondPrint(); dvd.derivedVirtualDiamond_print(); cout << "基类DerivedVirtual_2的typeinfoPtr指针的存储位置 = " << hex << ((int*)(*((int*)(&dvd) +3)) - 1) << endl; cout << "基类DerivedVirtual_2的typeinfoPtr指针的值也即DerivedVirtual_2's type_info的首地址 = " << hex << *((int*)(*((int*)(&dvd) +3)) - 1) << endl; cout << "基类DerivedVirtual_2的虚函数表中第一个slot的值也即虚函数DerivedVirtual_2::derivedVirtual_2_print()的入口地址 = " << hex << *(int*)(*((int*)(&dvd) + 3)) << endl; pFun pDerivedMultiVirtual2Print = (pFun)(*(int*)(*((int*)(&dvd) + 3))); pDerivedMultiVirtual2Print(); dvd.derivedVirtual_2_print(); cout << "基类Base的typeinfoPtr指针的存储位置 = " << hex << ((int*)(*((int*)(&dvd) + 8)) - 1) << endl; cout << "基类Base的typeinfoPtr指针的值也即Base's type_info的首地址 = " << hex << *((int*)(*((int*)(&dvd) + 8)) - 1) << endl; cout << "基类Base的虚函数表中第一个slot的值也即虚函数DerivdeVirtualDiamond::~DerivdeVirtualDiamond()的入口地址 = " << hex << *(int*)(*((int*)(&dvd) + 8)) << endl; cout << "基类Base的虚函数表中第二个slot的值也即虚函数DerivdeVirtualDiamond::base_print()的入口地址 = " << hex << *((int*)(*((int*)(&dvd) + 8)) + 1) << endl; pFun pDerivedBasePrint = (pFun)(*((int*)(*((int*)(&dvd) + 8)) + 1)); pDerivedBasePrint(); dvd.base_print();}
运行结果:
参考:
[1] 《深度搜索C++对象模型》,候捷 译.
测试代码:http://download.csdn.net/detail/corcplusplusorjava/9172463
- Objective-C对象模型
- Objective-C对象模型
- objective C 对象模型
- C ++ 对象模型
- Objective-C 对象模型
- 【C++】对象模型
- Objective-C对象模型
- C/C++的对象模型
- Objective-C的对象模型
- 图解Objectvie-C对象模型
- C/C++的对象模型
- Objective-C对象模型--类对象和元类对象
- 深度探索C++对象模型
- Objective-C 对象和消息模型
- Objective-C对象模型及应用
- Objective-C对象模型及应用
- Objective-C对象模型及应用
- Objective-C对象模型及应用
- 安卓开发艺术探索笔记知识点
- viewpage与scrollview共存,viewpager不显示的解决办法
- vs2008快捷键极其技巧 转载
- Linux Pmap 命令:查看进程用了多少内存
- Swift - 简单实现一个tableView
- C++对象模型
- Reactjs 之 mixins
- Hibernate4探索之旅之前言
- php 将秒数转换为时间(年、天、小时、分、秒)
- Linux下如何修改MySQL物理目录
- uva 1336 - Fixing the Great Wall
- cocos2dx 3.x 实现 A星(A*)(A-star)算法自动寻路(一)
- 由于系统缓冲区空间不足或队列已满,不能执行套接字上的操作(MaxUserPort,TcpTimedWaitDelay)
- js对象如何实现数组索引功能并且自定义自己的方法 (4种方法)