对于类中的非静态数据成员,每一个类对象都拥有一个副本,即每个对象的同名数据成员可以分别存储不同的数值,这是保证每个对象拥有区别于其他对象的特征的需要。而类中的静态成员则是解决同一类的不同对象之间的数据和函数共享问题的。静态成员的特征是不管这个类创建了多少个对象,它都只有一个副本,这个副本由所有属于这个类的对象共享。这种共享与全局变量或全局函数相比,既没有破坏数据隐藏的原则,又保证了安全性。
静态成员表示整个类范围的信息,其声明以static关键字开始,包括静态数据成员和静态成员函数。
9.1 静态数据成员
静态数据成员声明时要使用关键字static
静态数据成员在每个类对象中并不占有存储空间,它只是在每个类中分配有存储空间,供所有对象公用。静态数据成员的值对每个对象都是一样的,它的值可以被任何一个对象更新,从而实现了同一类的不同对象之间的数据共享。
静态数据成员具有静态生存周期,必须对它进行初始化。静态数据成员初始化的一般格式如下:
<数据类型><类名>::<静态数据成员名>=<初始值>;
在对静态数据成员初始化时应该注意:
(1)由于在类的声明中仅仅是对静态数据成员进行了引用声明,因此必须在文件作用域的某个地方对静态数据成员进行定义并进行初始化,即应在类体外对静态数据成员进行初始化(静态数据成员的初始化与它的访问控制权限无关)。
(2)静态数据成员初始化时前面不加static关键字,以免与一般静态变量或对象混淆。
(3)由于静态数据成员时类的成员,因此在初始化时必须使用作用域运算符限定它所属的类。
例1 分析下列程序的输出结果
#include<iostream>
using namespace std;
class Point
{
private:
int X, Y, Z;
static int count;
public:
Point(int x = 0, int y = 0, int z = 0) :X(x), Y(y), Z(z)
{
count++;
}
void Display()
{
cout << X << "," << Y << "," << Z<<endl;
cout << count << endl;
}
};
int Point::count = 0;//初始化静态成员
int main()
{
Point p1(1, 2, 3), p2(4, 5, 6);
p1.Display();
p2.Display();
return 0;
}
在上面的例子中,类的数据成员count声明为静态成员,用于对类的对象计数。静态数据成员的的初始化是在类体外进行的初值为0,每建立一个类的对象,count的值就加1。
9.2 静态成员函数
公有的静态数据成员可以直接访问,但私有的或保护的静态数据成员却必须通过公有的接口进行访问,一般将公有的接口定义为静态成员函数。
使用static关键字声明的成员函数静态成员函数,静态成员函数也属于整个类而不属于类的某个对象,他是该类的所有对象共享的成员函数。
静态成员函数可以在类体内定义,也可以在类外定义。当在类外定义时,要注意不能使用static关键字作为前缀。
由于静态成员函数在类中只有一个副本,因此它的访问对象的成员受到一些限制:静态成员函数可以直接访问类中说明的静态成员·,但不能直接访问类中说明的非静态成员;若要访问非静态成员必须通过参数传递的方式得到相应对象,再通过对象进行访问。
例2 分析下列程序的输出结果
#include<iostream>
using namespace std;
class Point
{
private:
int X, Y, Z;
static int count;
public:
Point(int x = 0, int y = 0, int z = 0) :X(x), Y(y), Z(z)
{
count++;
}
static void Display(Point& p);
};
void Point::Display(Point& p)
{
cout << p.X << "," << p.Y << "," << p.Z << endl;
cout << count << endl;
}
int Point::count = 0;//初始化静态成员变量
int main()
{
Point p1(1, 2, 3), p2(4, 5, 6);
p1.Display(p1);
p2.Display(p2);
return 0;
}
公有的静态成员既可以直接使用作用域运算符通过类名进行访问,也可以通过类的任何对象进行访问,但是建议使用前者进行访问,即:
<类名>::<静态数据成员名>
或
<类名>::<静态数据成员名>(<参数表>)
使用类名和作用域运算符进行访问可以清楚地表达出静态成员是属于这个类的,而不是属于类中的某一个对象。另外,由于静态成员在该类的任何对象被建立之前就已经存在了,因此静态成员可以在程序内部不依赖于任何对象被访问,即使没有建立该类的任何一个对象时也可以使用作用域运算符通过类名访问类的公有静态成员。
参考《全国计算机等级考试二级教程——C++语言程序设计》