类的静态成员
面向对象的设计方法兼容数据的保护和共享,静态成员的提出是为了解决不同对象之间数据共享问题的。例如要统计人员个数,出现次数等等都需要用到静态处理。静态成员,指的是在c++类中声明成员时可以加上static关键字,这样声明的成员就叫做静态成员(包括静态数据成员和静态成员函数)。
首先我们要搞懂静态变量生存的周期
静态成员变量在程序启动时被分配,在程序结束时被释放,其生命周期为程序的生命周期。基于这个类的所有对象只有一个静态成员变量的拷贝,所以一个函数结束时,静态变量仍然在内存中的静态存储区里保存,直到脚本结束才会被注销。
1.静态数据成员
如果我们需要面向对象中“类属性”,这个属性为整个类拥有,不属于其中某一个对象,从而体现了整个类的数据共享。此时我们就用用static声明静态成员。
由于静态数据成员不属于任何一个对象,我么可以用类名对他进行访问,一般用法是类名::标识符,但是在类中也要进行定义性声明。类的静态数据成员需要类之外定义是因为要单独给他们分配空间。
例如书上5-4中具有静态成员的point类
#include<iostream> using namespace std; class point { public: point(int x=0,int y=0):x(x),y(y){ count++; } point(point &p); ~point(){ count--; } void getX(){ cout << x; } void getY(){ cout << y; } void showcount(){ cout << "count=" << count << endl; } private: int x,y; static int count;//声明 }; int point::count=0;//用类名限定静态成员定义和初始化 point::point(point &p){ x=p.x; y=p.y; count++; } int main(){ point a(1,1); a.showcount(); point b(a); b.showcount(); return 0; }
在这个简单的例子中,我们可以看到point中的count被声明为静态,每新增一个对象count就加一。我们需要注意的就是count的定义和初始化在类外进行的。虽然这个count是私有成员在这种特殊场合可以进行初始化,但在其他函数例如主函数就不能调用count了。
2.静态函数成员
上面例子中如果我们如何输出count的初始化值呢,这时还没有创建对象,如果我们直接这样不出意外会报错,因为这时我们不能直接通过类名调用函数。
main(){ point::showcount(); point a(1,1); }
这时我们需要的就是静态成员函数了。静态成员函数就是通过使用static关键字声明的函数。同静态数据成员一样,静态成员函数也是属于一个类,由同一个类所有对象共同拥有,也体现了数据共享。静态成员函数可以直接访问类的静态数据和函数成员,而一般函数必须同过对象名。
这两段代码的区别只是将输出函数改成了静态类型,达到的输出效果完全一样。相比之下,静态成员函数可以脱离对象直接调用,这是他很好的一个优点。
#include<iostream> using namespace std; class point { public: point(int x=0,int y=0):x(x),y(y){ count++; } point(point &p); ~point(){ count--; } void getX(){ cout << x; } void getY(){ cout << y; } static void showcount(){ cout << "count=" << count << endl; } private: int x,y; static int count;//声明 }; int point::count=0;//用类名限定静态成员定义和初始化 point::point(point &p){ x=p.x; y=p.y; count++; } int main(){ point::showcount(); point a(1,1); point::showcount(); point b(a); point::showcount(); return 0; }
最后我们对比一下静态成员函数和普通函数:
首先普通数据成员属于类的一个具体的对象,只有对象被创建了,普通数据成员才会被分配内存。而静态数据成员属于整个类,即使没有任何对象创建,类的静态数据成员变量也存在。其次因为类的静态数据成员的存在不依赖与于任何类对象的存在,类的静态数据成员应该在代码中被显式地初始化,一般要在类外进行,例如上例。我们可以为静态成员提供const整数类型的类内初始值,类的静态成员函数无法直接访问普通数据成员(可以通过对象名间接的访问),而类的任何成员函数都可以访问类的静态数据成员。