C++类创建时,会产生一个默认的赋值运算符函数:A& operator=(const A&);
普通类实例之间赋值可能没问题,但当类成员变量中有指针引用的动态内存时,复制后只是简单地将指针值复制,而没有将其指向的动态内存也拷贝一份,这样即多个类实例内的指针指向同一动态内存,当类实例析构时,会导致这块动态内存delete多次而产生错误。这也就说明需要我们对一些特别的类重载其赋值运算符函数,即深拷贝!
这里只是介绍一下深拷贝的意思,不具体细说。下面是讨论赋值运算符函数的返回值。看下代码:
#include <iostream>
using namespace std;
class A{
public:
int a;
A(){};
A(int n){ this->a = n; }
operator int(){
cout<<"use int conventor \n";
return this->a;
}
A& operator=(const A a){
this->a = a.a;
return *this;
}
};
int main(){
A a, b, c(3);
a = b = c;
cout<<a.a<<endl;
return 0;
}
在百度搜索时,看很多童鞋不理解为什么好多的运算符重载都返回引用?这是为了进行串联的操作,例如a = b = c =.... , cout<<a<<b<<c...
那么如果不写A&,默认的返回值是什么呢?答:是int类型
上面的代码,有两种operator函数,一种是“类型转换函数”,另一种是“操作符重载函数”。其中“类型转换函数“不能声明其返回值,大家可以这样理解,类型转换函数就是要将本类转换为其他类型,operator后面紧跟着目标类型,也就不需要再多余得写明返回值。而”类型转换函数“如果不写返回值,默认的是int类型。
下面,来看几种情况:
class A{
public:
int a;
A(){};
A(int n){ this->a = n; }
operator int(){
cout<<"use int conventor \n";
return this->a;
}
A& operator=(const A a){
this->a = a.a;
return *this;
}
};
int main(){
A a, b, c(3);
a = b = c;
cout<<a.a<<endl;
return 0;
}
结果是:3
分析:a = b = c; 表达式从右往左执行,先b=c,调用了operrator=,返回b的引用,然后a = b,再调用一次operator=,返回a的引用
class A{
public:
int a;
A(){};
A(int n){ this->a = n; }
operator int(){ //与上面相比,去掉了其返回值A&
cout<<"use int conventor \n";
return this->a;
}
operator=(const A a){
this->a = a.a;
return *this;
}
};
int main(){
A a, b, c(3);
a = b = c;
cout<<a.a<<endl;
return 0;
}
结果是:
use int conventor
use int conventor
3
分析:前面说过,”运算符重载函数“的默认返回值是int类型,所以在return *this时,会调用operator int,将A类型转换成int类型。所以b=c时,调用operator=,然后在返回时又调用了一次operator int,返回了int值,为3。接下来就变成了 a= 3的表达式,这个怎么办呢?这个表达式,会调用A(int n)这个”转换构造函数“,将3转换成A的一个临时对象,然后调用operator=将临时对象复制到a中,同样,operator=在返回时又调用了一次operator int
大家可以在A(int n)中加一个cout<<"conventor construcor"的输出语句,再次看看效果。
class A{
public:
int a;
A(){};
explicit A(int n){ this->a = n; } //与上面相比,加上了一个explicit
operator int(){
cout<<"use int conventor \n";
return this->a;
}
operator=(const A a){
this->a = a.a;
return *this;
}
};
int main(){
A a, b, c(3);
a = b = c;
cout<<a.a<<endl;
return 0;
}
无法通过编译:
error C2679: binary '=' : no operator defined which takes a right-hand operand of type 'int' (or there is no acceptable conversion)
上面的例子中,说了会调用A(int n)这个“转换构造函数”,当给这个函数加上explicit时,就说明该构造函数只允许显示调用,而不能用于隐式的转换。
explicit A(int n){ .... },在声明类实例时:
A a = 3; \\错误
A a(3); \\正确
A a; a = 3; \\错误
所以,当遇到上面例子的 a=3这个过程时,就会因为找不到转换函数而报错!
关于类型转换和运算符重载其实挺迷惑人的,大家自己多动手写例子,慢慢推导体会!看几遍别人的推导分析,比不上自己一次的动手实验!