8.7.5 static数据成员
C++允许使用static(静态存储)修饰数据成员,这样的成员在编译时就被创建并初始化了(与之相比,对象是在运行时才被创建的),且其实例只有一个,被所有该类的对象共享,就像住在同一宿舍里的同学共享一个房间号一样。静态数据成员和第6章中介绍的静态变量一样,程序执行时,该成员已经存在,一直到程序结束,任何对象都可对其进行访问。static数据成员的用法见代码8.17。
代码8.17 static数据成员的用法StaticMember
<———————————————文件名:computer.h——————————————> 01 #include<iostream> 02 using namespace std; 03 class computer 04 { 05 private: 06 float price;//float型数据成员price,表示价格 07 static float total_price;//static成员,总价,不依附于某个对象 08 public: 09 computer(const float p)//构造函数,模拟买电脑的操作,对total_price进行累加 10 { 11 price=p; 12 total_price+=p; 13 } 14 ~computer()//析构函数,模拟退还电脑的操作,从total_price中减去 15 //所退电脑的price 16 { 17 total_price-=price; 18 } 19 void print()//输出函数 20 { 21 cout<<"总价:"<<total_price<<endl; 22 } 23 }; <———————————————文件名:example817.cpp————————————> 24 #include"computer.h" 25 float computer:total_price=0;//初始化 26 int main() 27 { 28 computer comp1(7000);//买入电脑1 29 cout<<"购买电脑1后"<<endl; 30 comp1. print(); 31 computer comp2(4999);//买入电脑2 32 cout<<"购买电脑2后"<<endl; 33 comp2. print(); 34 computer comp3(2500);//买入电脑3 35 cout<<"购买电脑3后"<<endl; 36 comp1. print();//此处调用comp1.print()、comp2.print()和comp3.print() 37 //输出结果相同 38 comp2.~computer();//退掉电脑2 39 cout<<"退掉电脑2后"<<endl; 40 comp3. print(); 41 return 0; 42 }
输出结果如下所示。
购买电脑1后 总价:7000 购买电脑2后 总价:11999 购买电脑3后 总价:14499 退掉电脑2后 总价:9500
【代码解析】在代码第7行,computer.h文件中“static float total_price;”定义了float型静态数据成员total_price,则该成员为所有computer类的对象所共有,其对应的内存空间在程序编译时已被开辟,请注意example817.cpp中的语句“float computer:total_price=0;”,这条语句将total_price初始化为0,一定不能在类定义时对total_price初始化,事实上,类中的声明语句是向编译器描述应如何为数据成员分配内存,真正的内存分配是由example817.cpp中的定义性声明语句“float computer:total_price=0;”完成的。
对于total_price这样的静态数据成员,应在类声明之外使用单独的定义性声明语句完成其初始化,该语句中不能再使用static,初始化的基本格式如下所示。
类型类名:变量名=初始化表达式;//普通类型变量 类型类名:对象名(构造参数);//对象成员
注意
将静态数据成员的初始化放在cpp文件中,不要放在h文件中,因为程序中可能有多个cpp文件包含该h文件,这样会出现初始化的复本,引发错误。
类中的任何成员函数都可访问类对象的静态成员,代码8.17用创建对象模拟买入电脑这一操作,用撤销对象,显式调用析构函数模拟退货的操作,并在类的构造函数和析构函数中对total_price进行加减处理,实时计算了当前总价。
当然,如果将静态数据成员的访问权限声明为public,在外部可直接访问该成员,下列格式都是合法的。
cout<<comp1.total_price; cout<<comp2.total_price; cout<<comp3.total_price; cout<<computer:total_price;//推荐形式,不依赖于对象
推荐用不与特定对象相联系的方式访问静态数据成员,C++还提供了静态成员函数机制,这方面的相关内容稍后会有介绍,使用静态成员函数访问静态数据成员似乎是顺理成章的事。
要强调的是,如果静态数据成员使用const修饰(const与static没有前后之分),而且是整型、浮点型、布尔型或枚举型,但不能是类对象,数组(包括C风格字符串)、引用和指针,C++允许该成员在类定义中初始化,这样,便不能在外部再次对该成员进行定义性声明,但对该成员的引用性声明是允许的。
说明
VC 6并没有严格地实现最新的C++标准,即使是用const static修饰的数据成员,在VC 6中仍然要在类定义外部初始化,在类定义内初始化时VC 6的编译器会报错,而一些较新的编译器不会。