复制构造函数与赋值运算符
现在通过一个例子来说明复制构造函数与赋值运算符的区别:
#include <iostream.h>#include<string.h>
class String
{
private:
char *data;
public:
String(char *data1)
{
data=new char[10];
strcpy(data,data1);
}
~String(){delete []data;}
void getdata()
{
cout<<data<<'/n';
}
String(const String &);//复制构造函数
String &operator=(const String &);//重载=运算符
};
String::String(const String &rs)
{
if(this!=&rs)//
{
data=new char[10];
strcpy(this->data,rs.data);
}
}
String &String:: operator =(const String &rs)
{
if(this!=&rs)//避 免出现自己给自己赋值
{
delete[]data;//清空原来指针指向的内容,若出现自己给自己赋值,则会出现不可预计的错误,因为要利用旧资源为给新值分配新资源
data=new char[10];
strcpy(this->data,rs.data);//复制指针内容,建立新指向
}
return *this;
}
void main(void )
{
String s1("HELLO S1");
s1.getdata();
String s2(s1);
s2.getdata();
String s3=s1;//两者相同,都是调用复制构造函数
s3.getdata();
String s4("HELLO S4");
s4.getdata();
s4=s1;//赋值运算符
s4.getdata();
}
运行结果为:
HELLO S1
HELLO S1
HELLO S1
HELLO S4
HELLO S1
从上述程序可以看出,采用紫红色标注的两种方式,肯定是调用复制构造函数,并且新建立的对象从未调用过类的构造函数,原始对象与对象副本的指针指向的不是同一块内存(前一篇类的构造函数中有解释),避免出现对同一块内存释放两次而导致严重错误,若先将对象A初始化,然后再将对象B赋给对象A,则是调用赋值运算符,调用赋值运算符时,对象A原来的内容被简单替换为对象B的内容,若是常规成员则简单复制,若是指针,则必须先清空对象A中的指针成员所指向的内存空间,同样为了避免出现对同一块内存空间释放两次的错误,也需要给对象A的指针成员分配一个新的空间,来存放对象B指针的内容。
那么什么时候会调用复制构造函数呢?
除了上述两种情况之外,还有下面几种情况会调用复制构造函数。
如果函数的形参是类的对象,则在进行函数调用时,将自动调用复制构造函数,这也是复制构造函数中的形参如果不是对象引用会造成无限循环调用的原因。
如果函数的返回值是类对象,则在执行返回语句是将自动调用复制构造函数