注:以下大部分内容来源于 coursera 课程《C++程序设计》
- 静态成员:在定义前加了关键字static 的成员
- 包括静态成员变量和静态成员函数
- 与普通成员的差别:普通成员变量每个对象有各自的一份,静态成员变量一共就一份,为所有对象共享。sizeof()不会计算静态成员变量。
- 普通成员函数必须具体作用于某个对象,而静态成员函数并不具体作用于某个对象。
- 静态成员不需要通过对象就能访问。
- 静态成员变量本质上是全局变量,不依靠于对象。静态成员函数是全局函数。
如何访问静态成员?
- 通过类名::成员名
Crectangle:PrintTotal(); - 对象名.成员名
Crectangle r;
r.PrintTotal();
注意:虽然这里是r.PrintTotal,但是PrintTotal并不是作用在r上面的,这只是一种形式。 - 指针->成员名
Crectangle *p = &r;
p->PrintTotal(); - 引用->成员名
Crectangle &re = r;
int f = re.nTotalNumber;
例子:
考虑一个需要随时知道矩形总数和总面积的图形处理程序,可以用全局变量来记录总数和总面积。
思路:将nTotalNumber++写在构造函数里面,只要有矩形对象的生成,就会自动调用构造函数。
将nTotalNumber--写在析构函数里面,只要有矩形对象的消亡,就会自动调用析构函数。
class CRectangle{
private :
int w,h;
static int nTotalArea;
static int nTotalNumber;
public:
CRectangle(int w_,int h_);
~CRectangle();
static void 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;
}
//声明静态成员变量
int CRectangle::nTotalNumber = 0;
int CRectangle::nTotalArea = 0;
int main(){
CRectangle r1(2,2), r2(3,3);
//cout << CRectangle::nTotalNumber; // Wrong , 私有
CRectangle::PrintTotal();
r1.PrintTotal();
return 0;
}
- 在C++里面,静态成员变量你必须拿到所有的函数外面来单独的给它声明一下。 必须在定义类的文件中对静态成员变量进行一次说明或初始化。否则编译能通过,链接不能通过。
- 在静态成员函数中,不能访问非静态成员变量,也不能调用非静态成员函数。
void CRectangle::PrintTotal()
{
cout<<w<<nTotalNumber<<","<<nTotalArea<<endl;
//w是非静态成员变量,不能访问,此条语句错误。
}
*缺陷:忽略了复制构造函数。
在使用CRectangle类时,有时会调用复制构造函数生成临时的隐藏的CRectangle对象。
//构造函数
CRectangle::CRectangle(int w_, int h_)
{
w=w_;
h=h_;
nTotalNumber++;
nTotalArea += w*h;
}
//析构函数
CRectangle::~CRectangle(){
nTotalNumber--;
nTotalArea -= w*h;
}
这个构造函数里面,对TotalNumber和TotalArea进行增加,这是没问题的。但是并不是所有的CRectangle的对象都会用这个构造函数来初始化。 有可能有一些CRectangle的对象,它是用复制构造函数来初始化的,
例子1: 如果调用了一个以CRectangle对象作为形参的函数的时候,这个形参对象就是由复制构造函数初始化的。
例子2:调用了一个以CRectangle对象作为返回值的函数的时候,那这个返回值对象它也是用复制构造函数初始化的。
这样的对象它们生成的时候并没有走构造函数,也就是并没有增加TotalNumber和TotalArea, 但它们在消亡的时候,却一定要走析构函数,就会减掉TotalNumber和TotalArea, 所以这个时候问题就产生了,就会发生总数和这个总面积比实际的情况要少的情况。
例子3: 临时对象在消亡的时候也会调用析构函数。
如果一个函数的返回值是一个对象的话,那这个函数的返回值就是一个临时对象。
- 解决办法: 为CRectangle类编写一个复制构造函数。
我们自己写一个复制构造函数,在这个复制构造函数里面,除了我们做复制的工作以外,还要对这两个总数进行修改。
网友评论