10.3.3 静态成员函数
像静态数据成员一样,也可以创建一个静态成员函数,它为类的全体对象服务而不是为一个类的特殊对象服务。这样就不需要定义一个全局函数,减少了全局或局部名字空间的占用,把这个函数移到了类的内部。当产生一个静态成员函数时,也就表达了与一个特定类的联系。
可以用普通的方法调用静态成员函数,用点“.”和箭头“->”把它与一个对象相联系。然而,调用静态成员函数的一个更典型的方法是自我调用,这不需要任何具体的对象,而是像下面使用作用域运算符:
当在一个类中看到静态成员函数时,要记住:类的设计者是想把这些函数与整个类在概念上关联起来。
静态成员函数不能访问一般的数据成员,而只能访问静态数据成员,也只能调用其他的静态成员函数。通常,当前对象的地址(this)是被隐式地传递到被调用的函数的。但一个静态成员函数没有this,所以它无法访问一般的成员。这样使用静态成员函数在速度上可以比全局函数有少许的增长,它不仅没有传递this所需的额外开销,而且还有使函数在类内的好处。
对于数据成员来说,static关键字指定它对类的所有对象来说,都只占有相同的一块存储空间。与定义对象的静态使用相对应,静态函数意味着对这个函数的所有调用来说,一个局部变量只有一份拷贝。
下面是一个静态数据成员和静态成员函数在一起使用的例子:
因为静态成员函数没有this指针,所以它既不能访问非静态的数据成员,也不能调用非静态的成员函数。
注意在main()中,一个静态成员可以用点或箭头来选取,把那个函数与一个对象联系起来,但也可以不与对象相联系(因为一个静态成员是与一个类相连,而不是与一个特定的对象相连),而是用类的名字和作用域运算符。
这里有一个有趣的特点:因为静态成员对象的初始化方法,所以可以把上述类的一个静态数据成员放到那个类的内部。下面是一个例子,它把构造函数变成私有的,这样Egg类只有一个惟一的对象存在,可以访问那个对象,但不能产生任何新的Egg对象。
E的初始化出现在类的声明完成后,所以编译器已有足够的信息为对象分配空间并调用构造函数。
为了完全防止创建其他对象,还需要再做如下的工作:增加一个叫做拷贝构造函数(copy constructor)的私有构造函数。到目前为止,还不知道为什么必须这样做,因为在下章中才会讨论拷贝构造函数。然而,如果删除上面例子中定义的拷贝构造函数,那么就能像下面那样创建一个Egg对象。
这两条语句都使用了拷贝构造函数,所以为了禁止这种可能性,拷贝构造函数声明为私有的(不需要定义,因为它不会被调用)。第11章的大部分内容是对拷贝构造函数的讨论,所以,通过第11章的学习后,我们会明白是怎么一回事。