以类A为例。
A(const A&)
首先,它是一个构造函数,所以是用于对象的初始化。其次,它构造对象的规则是通过拷贝各个成员变量完成。
A& operator=(const A&)
对于一个对象的赋值(注意,不是初始化,初始化调用的是拷贝构造函数而不是重载运算符)。
#include
#include
using namespace std;
class A
{
public:
int num;
A(int num):num(num){
cout<<"A constructor"<<endl;}
A(const A& a){
num = a.num;cout << "A copy constructor" << endl;}
~A(){
cout << "~A" << endl;}
};
A getA()
{
A a(5);
cout << "getA a&:" << &a << endl;
return a;
}
int main()
{
A a = getA();
cout << "main a&:" << &a << endl;
system("pause");
return 0;
}
可以看出,函数getA内的对象a和main中用于接收getA返回值的a地址一样,且getA结束时未调用A的析构函数,且没有调用A的拷贝构造函数。这是因为:编译器觉得在函数getA中,初始化了一个对象a,之后又得返回它,而返回它之前正常的操作是:创建一个临时变量复制a,再析构a,再将临时变量的引用返回用于初始化或者赋值。编译器看到这么麻烦,于是想:我不如直接将a给你,这样也省去了复制和析构的成本。因此,用于初始化对象时,返回的对象和接收的对象地址相同。
#include
#include
using namespace std;
class A
{
public:
int num;
A(int num):num(num){
cout<<"A constructor"<<endl;}
A(const A& a){
num = a.num;cout << "A copy constructor" << endl;}
~A(){
cout << "~A&:" << this << endl;}
A& operator=(const A& a){
cout << "operator=,&a:" << &a << endl;num = a.num; return *this;}
};
A getA()
{
A a(5);
cout << "getA a&:" << &a << endl;
return a;
}
int main()
{
A a(1);
a = getA();
cout << "main a&:" << &a << endl;
system("pause");
return 0;
}
在 a = getA()该行,getA()返回的仍然是函数内部局部变量的引用,且返回后马上进行了operator=的函数调用(a = getA() 相当于 a.operator=(getA()))。而可以看到,最后面析构的对象仍然是getA()产生的a对象,这是因为到operator=运算符结束时,该对象的声明周期已经结束了(局部变量,跳出了函数栈,且没有其他对象引用它),所以会被析构。而=运算最后返回*this并没有触发析构以及拷贝构造函数,这是因为*this的声明周期还未结束(在main中定义的对象)所以没有被析构,同时因为返回的是A&,所以没有产生对象的复制。然而下面的非正规operator=的实现却又有不同
#include
#include
using namespace std;
class A
{
public:
int num;
A(int num):num(num){
cout<<"A constructor"<<endl;}
A(const A& a){
num = a.num;cout << "A copy constructor" << endl;}
~A(){
cout << "~A&:" << this << endl;}
// 返回的是一个A对象 而不是A对象的引用
A operator=(const A& a){
cout << "operator=,&a:" << &a << endl;num = a.num; return *this;}
};
A getA()
{
A a(5);
cout << "getA a&:" << &a << endl;
return a;
}
int main()
{
A a(1);
a = getA();
cout << "main a&:" << &a << endl;
system("pause");
return 0;
}
可以看出,在=运算符里面,调用了一次拷贝构造函数以及两次析构函数。调用拷贝构造函数的原因是:函数返回值类型对象,因此需要创建一个临时变量(暂且命名为tmp)对*this进行拷贝,之后再传回临时对象tmp的引用。在=结束后,发生了两次调用析构函数,第一次析构的对象地址并没有在之前出现过,应该是创建的tmp对象被析构;而第二次析构的对象是getA()产生的对象。以这个顺序析构的原因是:函数栈帧入栈时的顺序是:形参声明顺序的逆序 -> 返回值 -> 局部变量声明顺序。所以函数调用完毕后,栈帧按入栈相反顺序出栈,所以先析构返回值,再析构形参(本例形参为getA()产生的对象a)。若将=的结果用于初始化一个对象,则可证明只析构了形参。
#include
#include
using namespace std;
class A
{
public:
int num;
A(int num):num(num){
cout<<"A constructor"<<endl;}
A(const A& a){
num = a.num;cout << "A copy constructor" << endl;}
~A(){
cout << "~A&:" << this << endl;}
A operator=(const A& a){
cout << "operator=,&a:" << &a << endl;num = a.num; return *this;}
};
A getA()
{
A a(5);
cout << "getA a&:" << &a << endl;
return a;
}
int main()
{
A a(1);
A b = a = getA(); // 使用=运算的结果初始化对象b
cout << "main a&:" << &a << endl;
cout << "main b&:" << &b << endl;
system("pause");
return 0;
}
可以看到,=运算符结束后只调用了一次析构函数,且析构的对象是getA()产生的a