深度探索C++对象模型-第三章

说明:

不是很清楚的点,用下划线。

解答,用斜体;

重点,用粗体加粗;

第二章 Data 语意学

3.2 Data Member 的布局

非静态成员变量在class object中的排列顺序将和其声明的顺序一样的。但C++ standard允许编译器将多个access sections之中的data members自由排列,不必在乎他们的出现在class中的声明顺序。

3.3 Data Member 的存取

存取代价:

每一个member 的存取许可(private public protected),以及与class的关联,并不会导致任何空间上或执行时间上的额外负担——不论是在个别的class objects 或是在static data member 本身。

static data members:

静态数据成员(static data members) 被视为global变量,只有一个实体,存放在程序的data segment(数据段)之中,每次取static member 就会被内部转化为对该唯一的extern 实体的直接参考操作。若取一个static data member的地址,会得到一个数据类型的指针,而不是只想起class member的指针。

nonstatic data members:

只要程序猿在一个成员函数中直接处理一个非静态成员变量,“隐式类对象(this指针)”就会出现。

欲对一个nonstatic data member 进行存取操作,编译器需要把this指针(class object的起始地址)加上data member的偏移量。

非静态成员变量的偏移量在编译时期就可以获知,即使这个成员变量是属于被派生的类。因此存取效率高。

3.4 继承 与 Data Member

class Point2d{
    public:
        //....
    private:
        float x,y;
}
class Point3d{
    public:
        //....
    private:
        float x,y,z;
}

讨论上述结构,与 “提供继承结构” 有什么不同?

下面分四种情况讨论。

1.只要继承不要多态

具体继承(相对于虚拟继承)并不会增加空间或存储时间上的额外负担。这种情况base class和derived class的objects都是从相同的地址开始,其差异只在于derived object 比较大,用以容纳自建的静态数据成员,把一个derived class object指定给base class 的指针或引用(一定要通过指针或引用),并不需要编译器去调停或修改地址,提供了最佳执行效率。

2.加上多态

即在继承关系中,提供一个虚函数接口。

多态带来了程序弹性,但这种弹性会带来空间和存取时间的额外负担:

  1. 导入一个虚函数表 ,用来存储它所声明的每一个virtual functions的地址。
  2. 在每一个class object中导入一个vptr,提供执行期的链接,使每一个object能够找到相应的virtual table。
  3. 加强constructor,使它能够为vptr设定初始值,让它指向class 所对应的virtual table 。
  4. 加强destructor,使它能够消抹“指向class 相关virtual table”的vptr。

3.多重继承

class point2d{
    public:
        //....
    protected:
        float x,y;
}
class Vertex{
    public:
        //....
    protected:
        Vertex *next;
}
class Vertex3d: public point2d, public Vertex{ 
    //point2d是第一个base class,Vertex是第二个
    public:
        //....
    protected:
        float mumble;
}

对于一个多重派生对象,将其地址指定给“最左端(第一个)base class的指针”,情况和单一继承时相同,因为二者都指向了相同的起始地址;至于第二个或后面的base class 的地址指定操作,则需要将地址修改过:加上(或减去,如果是downcast)介于中间的base class subobject(s)的大小。

如果要存取第二个(或后面)的base class 中的一个data member ,会增加额外的成本吗?不需要付出额外的成本,因为members的位置在编译时期就固定了,因此存取member只是一个简单的offset的运算。

4.虚拟继承

这一部分比较难,并且各个编译器实现方式不同。

class如果含有一个或多个 virtual base class subobjects 将被分割为两部分:一个不变区域和一个共享区域。

  • 不变区域中的数据,不管后继如何衍化,总是能有固定的offset,这部分可以被直接存取;
  • 至于共享区域,所表现的就是virtual base class subobject ,这个部分数据,其位置因为每次派生操作而有变化,所以只能间接存取。

总结:

深度探索C++对象模型-第三章_第1张图片
虚拟继承内存布局

你可能感兴趣的:(深度探索C++对象模型-第三章)