一些基本知识点:
构造函数:
- 对象生成时构造函数自动被调用,对象一旦生成,就在也不能在其上执行构造函数。
- 若自己定义的构造函数带参数,则声明对象时也需要带参数,缺省函数除外。
复制构造函数起作用的三种情况:
- 当用一个对象去初始化同类的另一个对象时 如 Test a1=a2,区别于赋值 Test a1,a2;a1=a2;
- 如果某函数有一个参数是类 A 的对象,那么该函数被调用时,类A的复制构造函数将被调用;
- 如果函数的返回值是类A的对象时,则函数返回时,A的复制构造函数被调用。
C++产生临时对象的三种情况:
- 类型转换;
- 以值的方式给函数传参(可对应上面三种情况的2);注意如果是按引用传递,则不会生成临时变量。
- 函数需要返回一个对象时(对应3)。
下面是一个具体实例:
#include<iostream>
#include<windows.h>
using namespace std;
class CRectangle
{
private:
int w,h;
static int nTotalArea;
static int nTotalNumber;
public:
CRectangle(int w_,int h_);
~ CRectangle();
static void PrintTotal();
CRectangle AddOne();
};
CRectangle::CRectangle(int w_,int h_)
{
w=w_;
h=h_;
nTotalNumber ++;
nTotalArea +=w*h;
cout<<"constructor called"<<endl;
}
CRectangle::~CRectangle()
{
nTotalNumber --;
nTotalArea -=w*h;
cout<<"destructor called"<<endl;
}
CRectangle CRectangle::AddOne()
{
this->w ++;
return *this;
}
void CRectangle::PrintTotal()
{
cout<<nTotalNumber<<","<<nTotalArea<<endl;
}
int CRectangle::nTotalNumber=0;
int CRectangle::nTotalArea=0;
int main()
{
CRectangle r1(3,3),r2(2,2);
r2=r1.AddOne();
CRectangle::PrintTotal();
r1.PrintTotal();
system("pause");
return 0;
}
运行结果如下
在执行r2=r1.AddOne()时,由于AddOne函数返回对象类型,因此会调用复制构造函数生成临时的隐藏的CRectangle对象。而临时对象在消亡时会调用析构函数,减少nTotalNumber和nTotalArea的值,可是这些临时对象在生成时却没有增加它们的值,因此结果不是2,13,变成了1,1。要避免临时变量的影响,可以自己为CRectangle写一个复制构造函数,在里面改变nTotalNumber和nTotalArea的值。
CRectangle ::CRectangle(CRectangle & r)
{
w=r.w;
h=r.h;
nTotalNumber ++;
nTotalArea +=w*h;
cout<<"copy constructor called"<<endl;
}
但是编译报错
仔细检查后发现是函数AddOne返回类型出错,与复制构造函数所需参数类型不匹配。
修改前 CRectangle CRectangle::AddOne() 修改后 CRectangle & CRectangle::AddOne()
运行结果
可以看到,并没有调用复制构造函数,这是因为AddOne函数返回类型是引用,而不是对象类型。
注意,如果修改main函数如下
int main()
{
CRectangle r1(3,3),r2(2,2),r3=r1.AddOne();//调用AddOne函数对r3初始化
CRectangle::PrintTotal();
r1.PrintTotal();
system("pause");
return 0;
}
运行结果发生变化
这里调用了一次复制构造函数对r3进行初始化,但是没有生成临时对象。关于临时变量详细讲解可参考https://www.cnblogs.com/avril/archive/2010/10/20/1856320.html