一、问题引入
【笔记四十九:C++中的浅拷贝】有程序,当时我们编译可以通过,但是运行会出错,因为对象obj2=obj1进行赋值时,采用浅拷贝,导致对象析构时会对同一块内存空间析构两次。也就是说等号操作符“=”,默认是进行浅拷贝,我们需要对等号操作符进行重载,使其能够进行深拷贝。
原浅拷贝程序
#define_CRT_SECURE_NO_WARNINGS
#include
usingnamespacestd;
className
{
public:
//构造函数
Name(constchar*myp)
{
len=strlen(myp);//字符串的长度,不含'0'
p=(char*)malloc(len+1);//申请内存,要包含
strcpy (p,myp);//字符串放到类中
}
//析构函数
~Name()
{
if(p!=NULL)
{
free(p);
p=NULL;
len=0;
}
}
protected:
private:
char*p;//类里面含有指针,有可能出现深拷贝和浅拷贝的问题
intlen;
};
voidobjplay()
{
Name obj1("abcdefg");
Name obj2=obj1;//调用obj2的拷贝构造函数
//没写拷贝构造函数,使用C++编译器默认的拷贝构造函数
//C++编译器提供的拷贝构造函数是一个浅拷贝
//就是指针变量赋值了,但是指针变量所指向的内存空间没有被拷贝过去
//两个对象的指针属性指向同一块内存空间
}
intmain()
{
objplay();
system("pause");
return0;
}
二、重载等号操作符
按照步骤通过成员函数重载等号操作符:
(1)要承认操作符重载是一个函数,写出函数名称
operator=
(2)根据操作数,写出函数参数
obj2=obj1,操作数由两个,所以函数调用形式为:obj2.operator=(obj1)
(3)根据业务,完善函数返回值(看函数返回引用、元素还是指针),及实现函数业务
void operator=(Name &c1)
完成程序
#include
usingnamespacestd;
className
{
public:
//带参数构造函数
Name(constchar*myp)
{
len=strlen(myp);//字符串的长度,不含'0'
p=newchar[len+1];//申请内存,要包含
strcpy (p,myp);//字符串放到类中
}
//手工编写拷贝构造函数,使用深拷贝
Name(constName &obj)
{
len=obj.len;
p=newchar[len+1];
strcpy(p,obj.p);
}
//析构函数
~Name()
{
if(this->p!=NULL)
{
delete(this->p);
this->p=NULL;
len=0;
}
}
//等号操作符重载函数
voidoperator=(Name &obj1)
{
//先释放旧的内存
if(this->p!= NULL)
{
delete[]p;
len=0;
}
//根据obj1分配内存大小
this->len=obj1.len;
this->p=newchar[len+1];
//把obj1赋值
strcpy(p,obj1.p);
}
intgetLen()
{
returnlen;
}
protected:
private:
char*p;//类里面含有指针,有可能出现深拷贝和浅拷贝的问题
intlen;
};
voidobjplay()
{
Name obj1("abcdefg");//调用obj1的带参构造函数
Name obj2("abc");//调用obj2的带参构造函数
//调用等号操作符重载函数
obj2=obj1;
cout
//调用拷贝构造函数
//没有调用等号操作符重载函数
Name obj3=obj1;
cout
}
intmain()
{
objplay();
cout
system("pause");
return0;
}
我们单步调试程序,发现以下语句会调用等号操作符重载函数:
//调用等号操作符重载函数
obj2=obj1;
cout
但是,下面的语句会依旧调用考诶构造函数,不会调用等号操作符重载函数:
//调用拷贝构造函数
//没有调用等号操作符重载函数
Name obj3=obj1;
cout
具体原因目前我也不知道,知道了再写!
三、重载等号操作符支持链式编程
上面的程序中,如果我们再定义一个对象,然后obj2=obj1=obj3;我们发现编译错误,void类型不能做右值。这一个跟我们重载
等号操作符的实行顺序是从右往左的,也就是先执行obj1=obj3,然后函数返回void型,然后继续执行就是 obj2 = void,所以就会报错。
obj2=obj1=obj3执行时第一步需要将obj3赋给obj1,第二步obj1赋给obj2,所以我们在执行第一步时应该返回一个obj1就可以了,也就是返回一个Name类的对象,返回obj1对象本身,因此我们可以返回一个引用:Name &operator=(Name &obj1)
#include
usingnamespacestd;
className
{
public:
//带参数构造函数
Name(constchar*myp)
{
len=strlen(myp);//字符串的长度,不含'0'
p=newchar[len+1];//申请内存,要包含
strcpy (p,myp);//字符串放到类中
}
//析构函数
~Name()
{
if(this->p!=NULL)
{
delete(this->p);
this->p=NULL;
len=0;
}
}
//等号操作符重载函数
Name &operator=(Name &obj1)
{
//先释放旧的内存
if(this->p!= NULL)
{
delete[]p;
len=0;
}
//根据obj1分配内存大小
this->len=obj1.len;
this->p=newchar[len+1];
//把obj1赋值
strcpy(p,obj1.p);
return*this;
}
intgetLen()
{
returnlen;
}
protected:
private:
char*p;//类里面含有指针,有可能出现深拷贝和浅拷贝的问题
intlen;
};
voidobjplay()
{
Name obj1("abcdefg");//调用obj1的带参构造函数
Name obj2("abc");//调用obj2的带参构造函数
Name obj3("ab");
//调用等号操作符重载函数
obj2=obj1=obj3;
cout
}
intmain()
{
objplay();
cout
system("pause");
return0;
}
领取专属 10元无门槛券
私享最新 技术干货