类的静态数据成员
有时需要为某个类的所有对象分配一个单一的存储空间。在C语言中,可以用全局变量,
但这样很不安全。全局数据可以被任何人修改,而且,在一个项目中,它很容易与其他的名字
相冲突。如果可以把一个数据当成全局变量那样去存储,但又被隐藏在类的内部,并且清楚地
与这个类相联系,这种处理方法当然是最理想的了。
这一点可以用类的静态数据成员来实现。类的静态成员拥有一块单独的存储区,而不管我
们创建了多少个该类的对象。所有这些对象的静态数据成员都共享这一块静态存储空间,这就
为这些对象提供了一种互相通信的方法。但静态数据属于类,它的名字只在类的范围内有效,
并且可以是p u b l i c(公有的)、p r i v a t e(私有的)或者p r o t e c t e d(保护的)。
1.定义静态数据成员
因为类的静态数据成员有着单一的存储空间而不管产生了多少个对象,所以存储空间必须
定义在一个单一的地方。当然以前有些编译器会分配存储空间,但现在编译器不会分配存储空
间。如果一个静态数据成员被声明但没有定义时,连接器会报告一个错误。
定义必须出现在类的外部(不允许内联)而且只能定义一次,因此它通常放在一个类的实
现文件中。这种规定常常让人感到很麻烦,但实际上它是很合理的。例如
class A{
static int i;
public:
//
};
之后,在定义文件中:
int A::i=1;
在这里,类名和范围分解运算符用于指定了i的范围。
有些人对A : : i是私有的这点感到疑惑不解,还有一些事似乎被公开地处理。这不是破坏了
类结构的保护性吗?有两个原因可以保证它绝对的安全。第一,这些变量的初始化唯一合法是
在定义时。事实上,如果静态数据成员是一个带构造函数的对象时,可以调用构造函数来代替
“=”操作符。第二,一旦这些数据被定义了,终端用户就不能再定义它—否则连接器会报告
错误。而且这个类的创建被迫产生这个定义,否则这些代码在测试时无法连接。这就保证了定
义只出现一次并且它是由类的构造者来控制的。
2.静态数组的初始化
对所有的静态数据成员,我们必须提供一个单一的外部定义。这些定义必须有内部连接,
所以可以放在头文件中。初始化静态数组的方法与其他集合类型的初始化一样,但不能用自动
计数。除此之外,在类定义结束时,编译器必须知道足够的类信息来创建对象,包括所有成员
的精确大小。
class Values{
static const int size;
static const float table[4];
}
const int Values::size=100;
const float Values::table[4]={1.1,1.2,1.3,1.4};
3.局部类中不能有静态数据成员
局部类是在函数内部定义的类,其中不能有静态数据成员
4.静态成员函数
像静态数据成员一样,我们也可以创建一个静态成员函数,它为类的全体服务而不是为一
个类的部分对象服务。这样就不需要定义一个全局函数,减少了全局或局部名字空间的占用,
把这个函数移到了类的内部。当产生一个静态成员函数时,也就表达了与一个特定类的联系。
静态成员函数不能访问一般的数据成员,它只能访问静态数据成员,也只能调用其他的静
态成员函数。通常,当前对象的地址( t h i s)是被隐含地传递到被调用的函数的。但一个静态
成员函数没有t h i s,所以它无法访问一般的成员函数。这样使用静态成员函数在速度上可以比
全局函数有少许的增长,它不仅没有传递t h i s所需的额外的花费,而且还有使函数在类内的好
处。
用s t a t i c关键字指定了一个类的所有对象占有相同的一块存储空间,函数可以并行使用它,
这意味着一个局部变量只有一个拷贝,函数每次调用都使用它。