看到《C++ Primer》中的一句话,才想起分析一下这个问题:“static 数据成员的类型可以是该成员所属的类类型。非 static 成员被限定声明为其自身类对象的指针或引用”
这两个问题的关键点在于static是属于类而不属于任何一个对象,这点一眼可以看出。深究细节的时候发现谭浩强版《C++ 程序设计》296页中的一段话可以辅助理解这个问题:
“如果只声明了类而未定义对象,则类的一般数据成员是不占内存空间的,只有在定义对象时,才为对象的数据成员分配空间。但是静态数据成员不属于某一个对象,在为对象分配的空间中不包括静态数据成员所占的空间。静态数据成员是在所有对象之外单独开辟空间。只要在类中定义了静态数据成员,即使不定义对象,也为静态数据成员分配空间,他可以被引用。”
根据这段说明,假设声明一个类:
1 class Bar { 2 private: 3 int a; 4 int b; 5 static Bar mem1; // ok 6 };
在定义一个Bar对象A的时候,因为mem1不属于任何对象,所以A所需的空间只需关注a和b的空间,是已知可计算的值。又因mem1本身是用Bar定义的一个对象,自然它占空间的大小与A相同,只是鉴于static的成员特性,在定义任何对象之前,mem1已经存在于一个单独开辟的空间。
标题中的第二个问题就不同,假设它的类的形式是这样的:
class Bar2 { private: int c; int d; Bar2 mem2; // error! };
mem2是非static类型成员,那么使用Bar2在定义对象的时候,首先要知道该类型Bar2需要的空间,也就是说你不知道Bar2的大小,需要计算,于是,你“形象的用”int+int+Bar2(实际空间计算规则链接:相关的规则计算实际所需空间大小),显然,这其中有一个未知数,编译器计算得不到结果,自然报错。
当“int+int+固定值”的时候,这个问题就得以解决,这时“固定值这个位置”,指针是一个不错的选择,因为指针本身占据4个字节空间,这点与它指向的对象大小无关。至于为什么“引用”也可以,那就需要了解一下“引用的本质”,在谭版《C++ 程序设计》194页有这么一句话:“声明b为a的引用,可以理解为:是变量b具有变量a的地址”,不过这句话只是点到为止,并没做更深的探讨。
2013-06-05
附录:
struct和从class的长度计算规则:
①在默认情况下,VC规定各成员变量存放的起始地址相对于结构的起始地址的偏移量必须为该变量的类型所占用的字节数的倍数。②各成员变量在存放的时候根据在结构中出现的顺序依次申请空间,同时按照上面的对齐方式调整位置,空缺的字节VC会自动填充。③同时VC为了确保结构的大小为结构的字节边界数(即该结构中占用最大空间的类型所占用的字节数)的倍数,所以在为最后一个成员变量申请空间后,还会根据需要自动填充空缺的字节。
附录内容摘自:“goodfunman的博客”的《sizeof(struct var) 的长度如何计算》