class Point3d{
public:
//...
private:
float x;
static List<Point3d*> *freeList;
float y;
static const int chunkSize = 250;
float z;
};
-
非静态数据成员在类对象中的排列顺序将和其被声明的顺序一样,任何中间介入的静态数据成员比如freeList和chunkSize都不会被放进对象布局中。
-
上面例子中,每一个Point3d对象是由3个float组成,次序是x,y;静态数据成员存在在程序的
data segment
中,和个别的类对象无关。 -
C++标准要求,在同一个访问级别(也就是private、public、protected等区段)中,成员的排列只需要符号较晚出现的成员在类对象中具有较高的地址即可。也就是说,各个成员并不一定需要连续排列。什么东西可能会介于被声明的成员之间呢?类的边界调整(alignmet)可能就需要填补一些bytes
-
编译器还可能会合成一些内部使用的数据成员,以支持整个对象模型。比如说
vptr
,编译器会将它安插在每一个内含虚函数的类对象中。vptr
会被在什么位置呢?传统上它会被放在所有明确声明的成员的最后,不过有些编译器会把vptr放在一个类对象的最前端。
C++标准也允许编译器将多个访问层级中的数据成员自由排列,不在乎它们出现的类声明的次数。举个例子:
class Point3d{
public:
// **
private:
float x;
static List<Point3d*> *freeList;
private:
float y;
static const int chunkSize = 250;
private:
float z;
};
其类大小和组成都与之前声明的那个相同。虽然说允许成员次序随意,但是基本上都是按照声明次序排列的
- 当前各家编译器都是把一个以上的访问层级连锁在一起,按照声明的次序,称为一个连续区块
- 访问层级的多少不会造成额外负担。也就是说不管有多少个private等,得到的类大小是一样的
下面这个函数模板,接受两个数据成员,然后判断谁先出现在类对象中。如果两个成员都是不同的assess sections中的第一个被声明者,该函数就可以用来判断哪一个section先出现:
template<class class_type,
class data_type1,
class data_type2>
char* assess_order(
data_type1 class_type::*mem1,
data_type2 class_type::*mem2){
assert(mem1 != mem2);
return mem1 < mem2
?"member 1 occurs first"
:"member 2 occurs first"
}
assert_order(&Point3d::z, &Point3d::y);
那么class_type被绑定为Point3d,data_type1和data_type2被绑定为float