重载赋值运算符
上面我们讨论了“对象赋值异常”的问题。当对象的成员变量是指针类型时,对象之间的赋值,应该要对指针成员变量进行特殊操作。
要解决这个问题,需要重载赋值运算符。那么,运算符的重载在后续章节深入学习。
在这里,我们预先学习“赋值运算符重载”的知识。是为了让知识点归纳连贯起来。让读者知道,对象的赋值存在浅拷贝的问题。需要重载赋值运算符,进行深拷贝,才可以解决问题。
所以,我们教学的方法,不是死板地列出C++的知识点,而是针对问题,分析问题,解决问题。当学习了运算符的重载之后,再回来看该章节也行。但是,我们需要知道的一个知识点是:对象赋值存在浅拷贝问题,需要重载赋值运算符,进行深拷贝。
下面是一个测试例子,重载了赋值运算符。
可以看到,使用stud对象给stud1对象赋值,当stud对象销毁之后,stud1对象的数据还是正常。因为我们增加了“重载赋值运算符”函数的定义,在该函数中,对涉及到指针类型的成员变量,进行内存申请和数据拷贝。该函数的定义如下:
voidoperator=(conststudents){
if(NULL!=name){
delete[]name;//如果name已经申请内存,先释放内存;
}
name=newchar[32];//申请内存
strcpy(name,s.name);//拷贝数据
if(NULL!=addr){
delete[]addr;//如果addr已经申请内存,先释放内存;
}
addr=newchar[32];//申请内存
strcpy(addr,s.addr);//拷贝数据
number=s.number;
}
可以看到,给对象赋值的时候,对象的name,addr是指针类型,那么,需要申请内存再拷贝数据。而且,如果name,addr成员变量不是NULL类型,可能是已经申请了内存空间,那么,我们对内存空间进行释放,再次申请新的内存空间。保证对象的指针成员变量得到合法的内存地址。
上面的代码,我们重载了赋值运算符,满足两个对象之间的赋值。那么,如果有如下的main()函数,会产生什么结果?
intmain(void){
studentstud1,stud2;
if(1){
studentstud("wkf","xxx.mylinux.vip",xxx);
stud1=stud2=stud;
}
stud1.print();
stud2.print();
return0;
}
编译异常,异常信息如下:
wkf
ubuntu:~/c++$g++test.cpp-oexetest.cpp:Infunction‘intmain()’:
test.cpp:55:error:nomatchfor‘operator=’in‘stud1=stud2.student::operator=(((conststudent)((conststudent*)(stud))))’
test.cpp:36:note:candidatesare:voidstudent::operator=(conststudent)
可以看到,执行stud1=stud2语句的时候,出现了错误。那么,为什么会这样?
执行stud2=stud;成功,但是,执行stud1=stud2语句失败?
这个问题,当深入学习运算符重载的时候,就可以解决。解决方法就是修改重载赋值运算符,如下:
studentoperator=(conststudents){
if(NULL!=name){
delete[]name;
}
name=newchar[32];
strcpy(name,s.name);
if(NULL!=addr){
delete[]addr;
}
addr=newchar[32];
strcpy(addr,s.addr);
number=s.number;
return*this;
}
此时,编译程序,运行OK。程序分析如下:
(1)执行stud1=stud2=stud;语句,分成两个步骤,先执行stud2=stud;语句,把得到的返回值再赋给stud1对象。
(2)执行stud2=stud;语句的时候,调用重载的赋值运算符,相当于:
stud2.operator=(stud);
此时,是stud2对象调用重载的赋值运算符函数,调用完之后,返回一个student对象的引用。所以,在重载赋值运算符中,赋值完之后,返回*this对象,就是返回stud2对象。
所以,把stud2对象返回,再赋值给stud1对象;相当于stud1=stud2;此时,才是正确的逻辑。