《深度探索C++对象模型》读书笔记2:C++对象模型,我的虚拟函数被放在哪里?

首先,让我们来看一下C++类对象中,各种成员是如何布局的,即C++对象模型。本篇内容也是今后讨论C++底层经常要用到的,因此在进一步深入研究C++的其他主题之前,了解一下本文的内容是非常必要的。

C++对象模型,从简单对象模型到表格驱动对象模型,几经演变,最终形成了C++标准中的对象模型。

 

1C++对象模型

众所周知,在C++类中,有两种数据成员:staticnonstatic,三种成员函数:staticnonstatict virtual

C++对象模型中,nonstatic数据成员被配置于每一个类对象实体内;

static数据成员则被存放在所有的类对象实体之外,即程序的data segment之中;

static nonstatic成员函数也被放在所有的类对象之外;

virtual function则以两个步骤实现:

1)    每一个类产生出一堆指向virtual functions的指针,放在一个表格中,这个表格被称为virtual tablevtbl)。

2)    每一个类对象被添加了一个指针,指向相关的virtual table,通常这个指针被称为vptrVptr的设定和重置都由每一个类的构造、析构函数和复制运算符自动完成。每一个类用以支持runtime type identificationRTTI)的type_info object也由virtual table指出,通常放在表格的第一项。

Point类对象为例,整个C++对象模型如下图所示:

 

这个模型的优点在于它的空间和存取时间的效率;主要缺点则是如果应用程序代码本身未改变,但所用到的类对象的nonstatic数据成员有所修改,那么应用程序的代码同样得重新编译。

 

2、加上继承之后呢?

C++的继承机制包括:单一继承、多重继承以及虚拟继承,其中在虚拟继承下,基类不管在继承链中被派生多少次,永远只会存在一个实体。

C++采用的继承模型并不运用什么间接性,直接将基类内容放置在派生类对象中。(在派生类对象中的基类部分被称为subobject。)因此,提供了对基类成员最紧凑而且最有效率的途径。缺点则是对于基类的任何改变,派生类都必须重新编译。

 

3、复杂的虚拟继承

当引入虚拟继承之后,则需要一些间接的基类表现方法。

MetaWare和其它编译器到今天仍然在使用cfront(第一个C++编译器)的原始实现模型,即在派生类中安插一些指针,每个指针指向一个虚拟继承类。

下面让我们来看一下cfront模型是怎么实现的,在这里,我们提供了四个类:

class Point2d { };

class Vertex : public virtual Point2d { };

class Point3d : public virtual Point2d { };

class Vertex3d : public Vertex, public Point3d { };

这四个类的对象模型如下图所示:

Microsoft编译器提供的方法是在派生类对象中导入了一个virtual base class table以便维护每一个virtual base class的地址。

Bjarne推荐的方法是在virtual function table中保存虚拟基类的offset(注意,这里不是地址),将virtual base class offset 和virtual function entries混杂在一起。

这种base class offset的实现模型如下图所示:

 

 

 

由于对虚拟基类的支持会带来额外的负担(将在以后的文章中详细阐述)以及高度的复杂性,每一种实现模型多少有点不同,而且还会随着时间而不断进化。  

对于一个virtual base class而言,最有效的一种运用形式就是:一个抽象的virtual base class,没有任何数据成员。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值