3.4 静态成员变量和静态成员函数
静态成员:在说明前面加了static关键字的成员。
class CRectangle{
private:
intw,h;
staticint nTotalArea;
staticint nTotalNumber;
public:
CRectangle(intw_,int h_);
~CRectangle();
staticvoid PrintTotal();
};
静态成员变量和普通成员变量的区别1)-2):
1)静态成员变量一共就一分,为所有对象共享。
2)sizeof运算符不会计算静态成员变量。
class Cmyclass{
intn;
staticint s;
};
sizeof(Cmyclass) == 4;
3)普通成员函数必须具体作用于某个对象,而静态成员函数并不具体作用于某个对象。
4)因此静态成员不需要通过对象就能访问。
例子:
(1)类名::成员名
CRectangle::PrintTotal();
(2)对象名.成员名
CRectangler; r.PrintTotal();
//注意这里并不是作用在r上的,这只是一个形式而已。下同。
(3)指针->成员名
CRectangle*p = &r; p->PrintTotal();
(4)引用.成员名
CRectangle & ref = r; int n =ref.nTotalNumber;
l 静态成员变量本质上是全局变量,哪怕一个对象都不存在,类的静态成员变量也存在。
l 静态成员函数本质上就是全局函数。
l 设置静态成员这种机制的目的是将和某些类紧密相关的全局变量和函数写到类里面去,看上去想一个整体,易于维护和理解。
例子:
考虑一个需要随之知道句型总数和总面积的图形处理程序
可以用全局变量来记录总数和总面积
用静态成员将这两个变量封装进类中,就更容易理解和维护
class CRectangle {
private:
intw,h;
staticint nTotalArea;
staticint nTotalNumber;
public:
CRectangle(intw_,int h_);
~CRectangle();
staticvoid PrintTotal();
};
CRectangle::CRectangle(int w_,int h_){
w= w_;
h= h_;
nTotalNumber++;
nTotalArea+= w*h;
}
CRectangle::~CRectangle(){
nTotalNumber--;
nTotalArea-=w*h;
}
void CRectangle::PrintTotal(){
cout<<nTotalNumber<<”,”<<nTotalArea<<endl;
}
在C++里面,对于静态成员变量,必须拿到外面来单独地声明一下!!
intCRectangle::nTotalNumber = 0;
intCRectangle::nTotalArea = 0;
//必须在定义类的文件中对静态成员变量进行一次说明
//或初始化。否则编译能通过,链接不能通过。
//声明的同时,可以对他初始化,也可以不对他进行初始化。
int main(){
CRectangler1(3,3),r2(2,2);
//cout<<CRectangle::nTotalNumber;//wrong,私有
CRectangle::PrintTotal();
r1.PrintTotal();
return0;
}
在静态成员函数中,不能访问非静态成员变量,也不能调用非静态成员函数。
这是因为静态函数不是作用在某一个对象上面的。
void CRectangle::PrintTotal(){
cout<<w<<”,”<<nTotalNumber<<”,”<<nTotalArea<<endl;//wrong!
}
如果此时这样调用:CRectangle::PrintTotal();//解释不通,不知道w到底是属于哪个对象的。
也不能调用非静态成员函数,因为非静态成员函数有可能调用非静态成员变量。
有严重缺陷。
这是因为我们有的时候忽略了复制构造函数。
问题是是否所有的CRectangle对象都会使用这个函数来初始化呢?
现在我们写了构造函数,所以编译器不会自动生成无参的构造函数,但是编译器会自动生成复制构造函数。
但是这样的对象在消亡的时候却调用了我们写的析构函数。GG了。
解决办法:
为CRectangle类写一个复制构造函数。
CRectangle::CRectangle(CRectangle & r){
w= r.w; h = r.h;
nTotalNumber++;
nTotalArea+=w*h;
}