第三章:Data语意学(The Semantices ofData)
1、Data绑定:Class的data绑定发生在整个Class声明完(右大括号出现)。因此当data member 与全局data同名时,会选择绑定到data member。
2、data member 的布局layout: class 中nonstatic datamembers 的声明顺序与其在class object 中的布局顺序同,中间插入的static data members 则放到整个程序的globl section 中(被视为一个globl 变量,但在class的声明范围内可见!),与个别的object 无关。
3、注意:object 的layout 只要求较晚出现的nunstatic data members 由较高的地址。并不保证data members 是连续存放的,期间可能插入其他,比如边界填充。当有vitual 时会为object 添加vptr指针,一帮放在所有members 的最后,也有编译器放在最前端。
4、data member的存取:对static datamembers 在不管继承体系多复杂,在整个程序中只有一份实体(就算一个对象都没有,依然存在一份实体)。 因此对staticdata members取地址,得到的是一个相应数据类型的指针,而不是class member 的指针。即:派生类对象与基类对象共享基类的静态数据成员
5、当多个class声明了一个名字类型相同的static data members 时,在程序的data segment 编译器将会采用name-magling 技术对每一个data member具有独一无二的程序识别代码。
6、对nonstatic data member 的存取通过(对象的起始地址+该变量的偏移量-1)直接操作。(对没有vitual base class 时)
7、当在由虚基类的继承体系中:Class A; class a:public A;
a aa;//对象aa a* p; //对象指针p
则 aa.datamem; p->datamem;
当存取由虚基类继承而来的data member时,会有重大差异:对象指针会有多态性问题,因此存取操作一定在执行进行,而直接由对象名存取时直接在编译期就可以完成。
8、在无虚函数的继承体系中:每一个drivedclass都会完整的包含其直接base class的全部data members (包括基类用于边界填充的部分,如果派生类由新添的data members,则放到其基类成员的最后(包括边界之后!!)),因此会因为每一级的边界填充而使得继承体系中布局膨胀(各级的边界填充累积)
9、单一继承并含有虚拟函数:继承一个Vptr指针。(Vptr一般放在数据成员的末端)
10、指向data member的指针:取非静态成员的地址:p=&a;//得到时该成员在该object的偏移量(+1??,注意如果有vptr时,考虑其放的位置)。
11、类体中的数据成员的声明前加上static关键字,该数据成员就成为了该类的静态数据成员。和其他数据成员一样,静态数据成员也遵守public/protected/private访问规则。同时,静态数据成员还具有以下特点:
1).静态数据成员的定义。
静态数据成员实际上是类域中的全局变量。所以,静态数据成员的定义(初始化)不应该被放在头文件中。
其定义方式与全局变量相同。举例如下:
xxx.h文件
class base{
private:
static const int _i;//声明,标准c++支持有序类型在类体中初始化,但vc6不支持。
};
xxx.cpp文件
const int base::_i=10;//定义(初始化)时不受private和protected访问限制.
注:不要试图在头文件中定义(初始化)静态数据成员。在大多数的情况下,这样做会引起重复定义这样的错误。
静态成员不可在类体内进行赋值,因为它是被所有该类的对象所共享的。你在一个对象里给它赋值,其他对象里的该成员也会发生变化。为了避免混乱,所以不可在类体内进行赋值。只能在类体外进行初始化。
一般形式:
数据类型类名::静态数据成员名=初值
注意:不能用参数初始化表对静态成员初始化。一般系统缺省初始为0。