数据成员
类的空间占用
|
考虑以下代码:
class X{
}__attribute__((packed));
class Y : virtual public X{
}__attribute__((packed));
class Z : virtual public X{
}__attribute__((packed));
class A: public Y, public Z{
}__attribute__((packed));
int main() {
cout<<sizeof(X)<<" "<<sizeof(Y)<<" "<<sizeof(Z)<<" "<<sizeof(A)<<endl;
return 0;
}
输出结果为:
1 8 8 16
需要注意的是上text大小则与下列因素有关:
支持虚有基类造成的负担。该负担反应在编译器插入的指针上,此指针要么指向虚函数的子对象,要么指向某个相关表格。
空虚类优化。编译器对空的虚有基类做出优化,使空虚有基类占用的 1 个字节不会表现在其子类中。
内存对齐。
本文中已经关闭内存对齐 |
因此,Y, Z 的大小与上述指针(该指针为 8 个字节)和编译器执行的优化处理有关(否则 Y, Z 就是 9 个字节了)。
由此可得:
sizeof(Y) = sizeof(X) + sizeof(指针) + sizeof(内存对齐)
但是此时由于编译器对 sizeof(X) 进行优化,使其大小为零,而本节中又关闭了内存对齐。
数据成员的绑定
该节说明的问题在现代 C++ 已经解决 |
考虑以下代码:
extern int x;
typedef int length;
class X{
public:
int getX(){
return x; // 此处将绑定到全局变量
}
private:
typedef float length; // 此处将报错
int x;
};
以上问题出现在旧式C++中,为了解决这个第一个问题,编译器将对成员函数的数据绑定推迟到类定义之后:
extern int x;
typedef int length;
class X{
public:
int getX(){
return x; // 此处将绑定到全局变量
}
private:
typedef float length; // 此处将报错
int x;
};
// 在此处为成员函数进行数据成员
而第二个问题则依赖于 防御性编程
:
所有的数据成员生命放置在类的开头处,以保证正确的绑定
所有的嵌套声明放置在类的开头
所有的类成员函数与其实现分离
数据成员的内存排列
|
C++标准对数据成员有一下规定:
同一权限区内的数据成员排列顺序与声明顺序相同(不一定连续)
由编译器生成的数据成员(如 vptr)可以排列在任意位置
不同权限区的数据成员顺序不做规定
此处静态成员不考虑在内 |
数据成员的存取效率
-
- 静态成员的存取没有任何空间或效率的代价。
因为其被储存在程序的数据段,通过
object.static_data
的方式只是一种便利手段。若多个类声明了相同名称的静态数据成员,则编译器会对其命名进行修饰
对数据成员的存取必定经过
this
,其方式是this + offset(data_member)