深入探索C++对象模型(一)关于对象

最新在看深入探索C++对象模型(Inside C++ object model),看的同时针对一些之前没有留意或者理解不深的内容整理一下读书笔记,方便之后复习,也希望可以帮助到有同样疑惑的人。

下面是第一章的内容整理,注:以下图片来源于原书

关于对象(Object Lessons)

1. C++在布局以及存取时间上的额外负担是由virtual引起。

这里指的是C++中虚函数以及虚继承机制,虚函数是C++中实现多态的主要手段,虚继承则是为了解决诸如菱形继承爷爷以上类在孙子以下类中出现多分重复数据提出的,详细的内容在后面的章节中由介绍,之后的笔记会再详细做整理。

2. 几种可能的对象模型

a. 简单对象模型:所有实际的成员不存储在对象本身的空间中,而是对象中通过指针的形式指向实际存储的成员,虽然该模型没有实际应用于真正的C++编译器上,但是关于索引和slot数目的观念,被应用到了C++的“指向成员的指针”观念之中(成员的指针在第三章中有详细讨论,之后会做记录)。


class Point{
public:
    Point(float xval);
    virtual ~Point();
    float x() const;
    static int PointCount();

protected:
    virtual ostream& print(ostream &os) const;
    float _x;
    static int _point_count;
};
C++对象模型中,nonstatic data members被配置于每一个class object之内,static data members则被存放在所有的class object之外。static和nonstatic function members也被放在所有的class object之外。virtual function则以两个步骤支持之:
1. 每个class产生出一堆指向virtual functions的指针,放在表格之中。这个表格被称为virtual table(vtbl)
2. 每一个class object被安插一个指针,指向相关的virtual table。通常这个指针被称为vptr。vptr的设定和重置都由每一个class的constructor、destructor和copy assignment运算符自动完成。每一个class所关联的type_info object(用以支持runtime type identification, RTTI)也经由virtual table被指出来,通常放在表格的第一个slot处

b. 表驱动对象模型:这个模型与上面的模型有一些类似,不过在这个模型中,成员信息被分成两部分,数据成员和成员函数,,虽然这个模型也没有应用于实际的C++编译器上,但是成员函数表这个概念却是大部分的虚函数借鉴的实现方式。




c. C++对象模型:这个是目前实际编译器所采用的对象模型,是由Stroustrup经由简单对象模型而来,在此模型中,非静态成员配置于每一个类对象中,静态成员则被存放类对象之外(静态存储区),成员函数(静态以及非静态)也被放置在类对象之外,至于虚函数,则通过如下两个步骤实现:一、每个类产生一堆指向虚函数的指针放在一个表格中,该表格称为虚表(virtual table: vtbl),注意这个虚表不会放到类对象中。二、每个类对象会加入一个指针(vptr),指向相关的虚表,该指针的设定和重置会由相应类的构造函数,析构函数,以及拷贝构造函数自动完成,每个类所关联的type_info object(用以支持RTTI: runtime type identification),通常会存储在表格的第一个slot处。该模型的优点在于空间以及存取时间的效率,缺点是如果类的非静态成员有所改变,即便是客户端的代码没有改变,客户端代码同样需要重新编译。


一个实际的例子,类X定义了一个拷贝构造函数,一个虚析构函数,一个虚函数foo(),则一个典型的X实例化对象的没存布局如下:


3. 关于类对象的大小(之后还会有详细的讨论),一般而言,一个类对象要考虑,所有非静态成员大小的总和 + 任何由于对齐(为了保证总线的运输量的最高效率,对象大小会向上调整为某个值的整数倍,对于32bit机器,该值通常为4)操作而加上去的空间 + 为了支持虚拟(virtual)机制而产生的额外负担(指向虚表的指针,指向虚基类的指针)。

4. 关于指针(或者引用,因为本质上来讲引用是通过指针来实现的),以内存需求的观点来说,指向一个整数的指针和指向某个对象的指针,或者指向某个模板对象的指针,他们没有什么不同,他们的内容都是一个机器地址,指向不同类型的指针,既不在其指针的表示法不同,也不在其内容(一个地址)不同,而是在其所寻址出来对象类型不同,也就是说,“指针类型”会教导编译器如何解释某个特定地址中的内存内容及其大小,在C++中,多态的一种使用方法就是使用基类的指针或者引用指向派生类, 例如 ZoomAnimal za("Joey"); ZoomAnimal* pza = &za; 则目前的内存布局可能如下:


加上多态之后的内存布局:


、‘

猜你喜欢

转载自blog.csdn.net/coolwriter/article/details/80550678