c++对象模型研究1:关于对象

 对象模型

和c不同,c是将数据和处理数据的函数分开的(数据流过程决定函数编写,过程式的);而c++把数据和处理数据的方法关联在了一起(对象发起动作,操纵数据)。那么像class一样将数据和方法包含在一起,甚至再用上模板是否会增加布局成本呢?

 

C++对象模式

在C++中,有两种类成员数据:static非static,以及三种类成员函数:static非staticvirtual

 

 

在C++对象模型中,非static成员数据被配置于每一个类对象之内,static成员数据则被放在所有类对象之外。static和非static成员函数也被放在所有的类对象之外。

 

 

C++在布局以及存取时间上主要的额外负担是由virtual引起,包括

1.虚函数机制(执行时绑定)

2.虚基类。还有一些多重继承下的额外负担。

 

virtual函数则以两个步骤支持之:

 

1.每一个类产生出一堆指向virtual函数的指针,放在表格之中。这个表格被称为virtual表。

2.第一个类对象被添加了一个指针,指向相关的virtual表。这个指针的设定和重置都由每一个类的构造函数,析构函数和拷贝赋值运算符自动完成。另外,虚函数表地址的前面设置了一个指向type_info的指针,RTTI(Run Time Type Identification)运行时类型识别是有编译器在编译器生成的特殊类型信息,包括对象继承关系,对象本身的描述,RTTI是为多态而生成的信息,所以只有具有虚函数的对象在会生成。

 

和c相比,c++的布局成本主要来自于virtual,virtual使得class object需要先找虚表,再由虚表找所在地,增加了耗费。而像nonstatic data menber,跟c中struct完全一样,所以这些并不会增加c++的布局成本(相对于c而言)。

 

对于C++中的单继承

C++实际模型是:对于一般继承是扩充已有存在的虚函数表;对于虚继承添加一个虚函数表指针。

 

对于C++中的多继承

1)每一个基类都有自己的虚函数表,基类各有虚表

2)子类的虚函数被放到第一个基类的虚函数表中,子类与第一个父类共用一张虚表

3)内存布局中,基类的排列顺序就是基类的声明顺序

4)重写:每一个基类的虚表中的fun都被重写成子类的fun,这样做就是为了解决不同的基类类型的指针指向同一个子类实例,而能够调用到实际的函数。

 

对于C++中的多继承中的虚继承

虚继承的子类,有单独的虚函数表,另外也单独保存一份父类的虚函数表。

 

 

如何访问成员?

 

 

 

数据成员如何访问(直接取址)?

 

 

 

跟实际对象模型相关联,根据对象起始地址+偏移量取得。

 

函数成员如何访问(间接取址)?

跟实际对象模型相关联,普通函数(nonstatic、static)根据编译、链接的结果直接获取函数地址;如果是虚函数根据对象模型,取出对于虚函数地址,然后在虚函数表中查找函数地址。

 

多态如何实现?

多态(Polymorphisn)在C++中是通过虚函数实现的。如果类中有虚函数,编译器就会自动生成一个虚函数表,对象中包含一个指向虚函数表的指针。能够实现多态的关键在于:虚函数是允许被派生类重写的,在虚函数表中,派生类函数对覆盖(override)基类函数。除此之外,还必须通过指针或引用调用方法才行,将派生类对象赋给基类对象。

 

为什么析构函数设为虚函数是必要的?

这个写在《改善程序与设计的具体做法(C++)》中的条款7中。

 

ps:

 

本质上一个引用通常是以一个指针来实现,而且是const指针。

 

 

 

参考:

《深度探索C++对象模型》

C++对象模型

 

posted @ 2018-08-17 17:45  _raindrop  阅读(131)  评论(0编辑  收藏  举报