C++允许将一个对象的值赋给另一个对象。
或许你认为这就是复制,然而,“复制”只在初始化对象的时候发生。
如果一个已经具有值的对象被改写了,那么更准确的来说就是“赋值”。
注意,C++提供的复制工具是复制构造函数,因为这是一个构构造函数,因此只能在对象创建的时候使用,而不能用在对象的赋值。
C++为所有的类提供了赋值工具,这个方法叫做赋值运算符,名称为operator=,实际上其实就是重载了=运算符。
例子:
#include <iostream>
#include <cstring>
using namespace std;
class A
{
private:
char *str;
public:
A(const char *s){
int len=sizeof(s);
str=new char[len+1];
strcpy(str,s);
}
//删除复制构造函数
A(const A &a)=delete;
~A(){
cout<<"start delete!"<<endl;
delete []str;
cout<<"delete complete!"<<endl;
}
A &operator=(const A &a){//赋值运算符
if(this==&a)//注意检测是否是自赋值
return *this;
int len=sizeof(a.str);
delete []str;//重新分配str的内存
str=new char[len+1];
strcpy(str,a.str);
cout<<"完成对象赋值"<<endl;
}
void show()const{
cout<<"str="<<str<<endl;
cout<<"address:&str="<<&str<<endl<<endl;
}
};
int main()
{
{
A a("hello");
cout<<"this is a:"<<endl;
a.show();
cout<<"this is b:"<<endl;
A b("world");
b.show();
b=a;//对象赋值
b.show();
/*
cout<<"this is c:"<<endl;
A c=b;//注意,这一个调用的也是复制构造函数,而不是赋值构造函数
//类似于声明的语句会调用复制构造函数,原因时A c=b;c当时还没创建,是不会调用operator=方法的。
c.show();
*/
}
}
结果:
可以看到,执行
b=a;//对象赋值
这一句的时候用到了赋值运算符。
如果没有定义赋值运算符,C++编译器会自动生成一个类似于默认复制构造函数行为的赋值运算符。
需要注意的是要注意检测自赋值的这种情况。
还有一种情况就是:
#include <iostream>
#include <cstring>
using namespace std;
class A
{
private:
char *str;
public:
A(const char *s){
int len=sizeof(s);
str=new char[len+1];
strcpy(str,s);
}
//删除复制构造函数
A(const A &a)=delete;
~A(){
cout<<"start delete!"<<endl;
delete []str;
cout<<"delete complete!"<<endl;
}
A &operator=(const A &a){//赋值运算符
if(this==&a)//注意检测是否是自赋值
return *this;
int len=sizeof(a.str);
delete []str;//重新分配str的内存
str=new char[len+1];
strcpy(str,a.str);
cout<<"完成对象赋值"<<endl;
}
void show()const{
cout<<"str="<<str<<endl;
cout<<"address:&str="<<&str<<endl<<endl;
}
};
int main()
{
{
A a("hello");
cout<<"this is a:"<<endl;
a.show();
/*
cout<<"this is b:"<<endl;
A b("world");
b.show();
b=a;//对象赋值
b.show();
*/
cout<<"this is c:"<<endl;
A c=a;//注意,这一个调用的也是复制构造函数,而不是赋值构造函数
//类似于声明的语句会调用复制构造函数,原因时A c=b;c当时还没创建,是不会调用operator=方法的。
c.show();
}
}
编译结果:
这说明了 A c=a;调用的不是赋值运算符而是复制构造函数。如何区分呢?
一般来说,类似于声明的使用的是复制构造函数,类似于赋值的使用的是赋值运算符。
当然,C++11也允许显式默认和删除赋值运算符,规则和复制构造和默认构造一样。