拷贝构造函数
一、作用
拷贝构造函数函数是将已存在对象生成相同类型的新对象。
二、原型
拷贝构造函数形参一定要有引用。有两个原因:
- 避免递归构造的形参对象发生栈溢出
- 节省对象销毁的开销
class CGoods
{
public:
CGoods()//构造函数
{
mname = new char[1]();
std::cout << "CGoods::CGoods()" << std::endl;
}
CGoods(float price)
{
mname = new char[1];
mprice = price;
std::cout << "CGoods::CGoods(float)" << std::endl;
}
CGoods(char* name, int amount, float price)
{
mname = new char[strlen(name) + 1]();
strcpy_s(mname, strlen(name) + 1, name);
mamount = amount;
mprice = price;
std::cout << "CGoods::CGoods(char*,int,float)" << std::endl;
}
~CGoods()//资源的统一释放
{
delete[] mname;
mname = NULL;
}
private:
char* mname;
int mamount;
float mprice;
};
int main()
{
CGoods good1;//调用默认的构造函数
CGoods good2(10.1);//调用带有一个float类型的构造函数
CGoods good3("car1",10,45000);//调用带有三个参数的构造函数
}
以上是简单的构造析构函数。拷贝构造函数的生成,加入以下代码:
CGoods(const CGoods& rhs)
{
mname = new char[strlen(rhs.mname) + 1]();
strcpy_s(mname, strlen(rhs.mname) + 1,rhs.mname);
mamount = rhs.mamount;
mprice = rhs.mprice;
}
以上只是浅拷贝,如果类中的成员变量有指针就要进行深拷贝
赋值运算符重载函数
一、定义
系统提供自定义类型的赋值
二、作用
- 提供对象赋值的方式
- 拿已存在的对象赋值给相同的类型的已存在的对象
三、设计的步骤
- 自赋值
- 释放旧的其他资源
- 开辟新的资源
- 成员赋值
CGoods& operator = (const CGoods& rhs)
{
if(this == &rhs)//自赋值
{
return;
}
delete[] mname;
mname = new char[strlen(rhs.mname) + 1]();
strcpy_s(mname, strlen(rhs.mname) + 1, rhs.mname);
mamount = rhs.mamount;
mprice = rhs.mprice;
std::cout << "CGoods::operator=(const CGoods&)" <<std::endl;
return *this;
}
四、赋值运算符的重载函数的返回值
1、返回值为void
void operator = (const CGoods& rhs)
{
if(this == &rhs)//自赋值
{
return;
}
delete[] mname;
mname = new char[strlen(rhs.mname) + 1]();
strcpy_s(mname, strlen(rhs.mname) + 1, rhs.mname);
mamount = rhs.mamount;
mprice = rhs.mprice;
std::cout << "CGoods::operator=(const CGoods&)" <<std::endl;
}
int main()
{
CGoods good1;
CGoods good2;
CGoods good3("car3", 10, 100000);
goodl = good2 = good3;//连续赋值
return 0;
}
我们将上述代码中的连续赋值这一块做以下分析:
- 首先这句连续赋值的语句先处理
good2 = good3
- 就相当于good2调用了opreator这个赋值运算符的函数,然后将goo3当成实参传递进去。如:
good2.operator = (good3);
- 由于函数头为void定义,所以函数没有返回值,就相当于
good1 = void
(void没有返回值,相当于等于0) - 所以这句会出错
所以为了实现连续赋值,函数的返回值不能是void.
我们将函数的返回值改为类类型和类类型的引用
2、返回值为CGoods
CGoods operator = (const CGoods& rhs)
{
if(this == &rhs)//自赋值
{
return;
}
delete[] mname;
mname = new char[strlen(rhs.mname) + 1]();
strcpy_s(mname, strlen(rhs.mname) + 1, rhs.mname);
mamount = rhs.mamount;
mprice = rhs.mprice;
std::cout << "CGoods::operator=(const CGoods&)" <<std::endl;
return *this;
}
分析如下:
- 还是先处理
good2 = good3
- 就相当于good2调用了opreator这个赋值运算符的函数,然后将goo3当成实参传递进去。如:
good2.operator = (good3);
- 他返回的是临时对象,临时对象就相当于good2对象的备份。
- 我们发现将good1赋值给临时对象是成功的
- 但是假设我们的赋值语句是:
(good1 = good2) = good3;
,他做的事情是将good1.operator = (good2)
- 最后的结果成了将good3的值赋值给了临时对象。违背了原语句的意思。
- 所以这种方法也是不可取的 。
3、返回值为CGoods&
CGoods& operator = (const CGoods& rhs)
{
if(this == &rhs)//自赋值
{
return;
}
delete[] mname;
mname = new char[strlen(rhs.mname) + 1]();
strcpy_s(mname, strlen(rhs.mname) + 1, rhs.mname);
mamount = rhs.mamount;
mprice = rhs.mprice;
std::cout << "CGoods::operator=(const CGoods&)" <<std::endl;
return *this;
}
由于返回的是引用,引用是一个别名,所以就是good2本身。
所以一般写赋值构造函数时返回的是类类型的引用。