深度探索C++对象模型----Data语义学

1 Data Member的绑定

对于下图的类:

深度探索C++对象模型----Data语义学_第1张图片

       X()中的x返回的是类内部的x,这是因为编译器对于这个的处理是,如果一个inline函数在类声明之后立刻被定义,但还是在整个类声明完成之后,才队这个成员函数的本体进行分析,所以x绑定的是类内部的x

       然而对于成员函数的参数列表则不是这样的,它们会在第一次遇见时被决议。例如如果类中有nested type names,而函数有参数列表有该类型的参数,但是这个类内的类型定义却在这个函数之后,则会出现错误。例如下面这个类的效果。

深度探索C++对象模型----Data语义学_第2张图片

        像以上这个例子,后面的length的定义会使前面的参考操作不合法。

         所以解决方法是,将“nested type 声明”放在类的开始处,就不会出现上述错误了。所以如果类中有自定义的结构体,而函数参数是结构体类型,则这个函数要在这个结构体定义之后定义才合法,否则是错误的。

2 Data Member的布局。

        深度探索C++对象模型----Data语义学_第3张图片

         成员布局:非静态成员在类对象的排列顺序与声明顺序一样,任何static成员如上面的freelist, chunksize都不会放进对象布局。他们存放在程序的data segment中。

但是同一种访问类型中的数据成员只符合“较晚出现的成员在类对象中有较高地址”,但是类数据成员间不一定连续,可能会有别的,例如为了对齐添加的一些bytes,还有就是编译器合成的vptr,这个一般被放在类对象成员的最后,但是有的编译器在最前。一般编译器都将一个以上的access sections连锁在一起,依照声明顺序连成区域,这些access sections的多少并不会招来其他负担。

3 Data Member的存取

Point3d origin;
origin.x = 0.0
Point3d origin, *pt =&origin;
origin.x=0.0;
pt->x = 0.0

上面两种经过对象和指针存取x的存在的差异:当point3d是一个继承类,而且继承结构中有一个虚基类,而且x是从虚基类继承而来的成员,有重大差异。因为不知道pt指向哪个类类型,所以也不能在编译器确定,要延迟到执行器。当然这是发生在指针pt存取,如果origin存取没有什么问题。

分两类讨论,有一点:类的存取许可,以及与类的关联,不会队成员的存取招致任何空间和时间的额外负担。

(1)静态数据成员,被视为全局变量,因为静态成员不在类对象中,所以存取静态成员不需要经过类对象,而且不管是有多么复杂的继承关系继承过来的,都一样。

而且存取一个静态成员的指针,会得到一个指向其数据类型的指针,而不是指向类成员的指针。

        如果有两个类有相同的静态成员变量,则在数据段有名称冲突,解决方法就是暗中队每个变量编码(name-mangling,就是通过一个算法推导出一个独一无二的名称)

(2)非静态数据成员,类中每次对非静态数据成员的存取,都会通过this指针存取,而且编译器需要把类对象的起始地址夹生数据成员的offset

origin._y = 0.0
=>&origin+(&Point3d::_y-1)
指向数据成员的指针,offset值总是被加上1,以便编译器区分出“指出类的第一个成员的数据成员的指针”和“没有指出任何成员的数据成员的指针”。。这以后有详细说明

而且这个offset是在编译期可以缺点的,甚至成员是基类子对下的成员也一样,所以存取一个非静态成员,效率和存取一个C struct或非继承类的成员是一样的。

Point3d *pt3d;
pt3d->x = 0.0
在 x是一个struct member, 一个class member,单一继承,多重继承都是一样的,但是如果是一个虚基类的成员,存取速度会稍慢。


你可能感兴趣的:(C++模型,C++)