类的静态成员
面向对象的设计方法兼容数据的保护和共享,静态成员的提出是为了解决不同对象之间数据共享问题的。例如要统计人员个数,出现次数等等都需要用到静态处理。静态成员,指的是在c++类中声明成员时可以加上static关键字,这样声明的成员就叫做静态成员(包括静态数据成员和静态成员函数)。
首先我们要搞懂静态变量生存的周期
静态成员变量在程序启动时被分配,在程序结束时被释放,其生命周期为程序的生命周期。基于这个类的所有对象只有一个静态成员变量的拷贝,所以一个函数结束时,静态变量仍然在内存中的静态存储区里保存,直到脚本结束才会被注销。
1.静态数据成员
如果我们需要面向对象中“类属性”,这个属性为整个类拥有,不属于其中某一个对象,从而体现了整个类的数据共享。此时我们就用用static声明静态成员。
由于静态数据成员不属于任何一个对象,我么可以用类名对他进行访问,一般用法是类名::标识符,但是在类中也要进行定义性声明。类的静态数据成员需要类之外定义是因为要单独给他们分配空间。
例如书上5-4中具有静态成员的point类
#include
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
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整数类型的类内初始值,类的静态成员函数无法直接访问普通数据成员(可以通过对象名间接的访问),而类的任何成员函数都可以访问类的静态数据成员。