您的位置:首页 > 编程语言 > C语言/C++

C++对象模型

2015-08-06 16:38 375 查看

基本C++对象模型

如下面的Base类定义:

其对象在内存中的分配如下:



在此模型中,non static数据成员被放置到对象内部,static数据成员(放置到全局数据区),static函数成员(放置到全局数据区),non static函数成员(放置到代码段)均被放到对象之外。对于虚函数的支持则分两步完成:

每一个class产生一堆指向虚函数的指针,放在表格中。这个表格称为虚函数表(virtual table,vtbl)。
每一个对象被添加一个指针,指向相关的虚函数表vtbl。称这个指针为vptr。vptr的设定和重置都由每一个class的构造函数、析构函数和拷贝赋值运算符自动完成。

另外,虚函数表的地址前面设置了一个指向type_info的指针,RTTI运行时类型识别,由编译器在编译时生成特殊类型的信息,包括对象继承关系,对象本身描述,RTTI是为多态而生成的信息,所以只有具有虚函数的对象才会生成。

这个模型的优点在于它的空间和存取时间的效率;缺点是如果应用程序本身未改变,但当其非静态的成员函数添加、删除或修改时,需要重新编译。

无重写的单继承

无重写,即派生类中没有与基类同名的虚函数。有如下派生类:

Base、Derived的类图如下所示:

Base的模型跟上面一样,不受继承的影响。Derived不是虚继承,所以是扩充已存在的虚函数表,所以结构如下所示:



有重写的单继承

派生类中重写了基类的print()函数。

Base、Derived_Overwrite的类图如下所示:

重写print()函数在虚函数表中如下:



C++中加入多继承

从单继承可以知道,派生类中只是扩充了基类的虚函数表。如果是多继承的话,又是如何扩充的呢?

每个基类都有自己的虚表;
子类中的成员函数被放到了第一个基类的表中;
内存布局中,其父类布局依次按声明顺序排列;
每个基类的虚表中的print()函数都被overwrite成了子类的print()。这样做就是为了解决不同的基类类型的指针指向同一个子类的实例,而能够调用到实际的函数。

上面的三个类中,Derived_Mutlip_Inherit继承自Base、Base_1两个类,Derived_Mutlip_Inherit的结构如下所示:



C++对象模型中加入虚继承

虚继承是为了解决重复继承中多个间接父类造成的二义性问题,所以不能简单的扩充每个基类的虚函数表,这样会造成基类有多个虚函数表。
虚继承的派生类的内存结构,和普通继承完全不同。虚继承的子类,有单独的虚函数表,另外也单独保存一份父类的虚函数表,两部分用0X00000000来做分界。派生类的内存中,首先是自己的虚函数表,然后是自己的数据成员,然后是0X00000000,然后就是基类的虚函数表和基类的数据成员。
如果派生类没有自己的虚函数,就不会有自己的虚函数表,但是派生类的数据成员和基类之间,仍然需要0X00000000来间隔。
因此,在虚继承中,派生类和基类的数据,是完全间隔的,先存放派生类自己的虚函数表和数据,中间以0X00000000间隔,最后保存基类的虚函数表和数据。如果派生类复写了基类的虚函数,则将派生类内存中基类的虚函数表的相应函数替换。

简单虚继承

简单虚继承的两个类Base、Derived_Virtual_Inherit1的关系如下所示:

Derived_Virtual_Inherit1的对象模型如下图:



菱形继承

菱形继承关系如下图:

Derived_Virtual的对象模型如下图:



【原创地址】:http://www.cnblogs.com/skynet/p/3343726.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: