一.本章主要介绍类中的编译器提供的拷贝构造函数和自定义拷贝构造函数、赋值运算符重载函数
-
用同类型对象初始化新对象时用到外部资源时需要调用自己定义的拷贝构造函数,防止发生浅拷贝
-
用同类型对象赋值给已存在的同类型对象在调用赋值运算符重载函数时,防止发生浅拷贝、内存泄漏、自赋值
接下来,上代码
头文件
//
// Created by yanpan on 2018/9/5.
//
#ifndef C_CGOODS_H
#define C_CGOODS_H
class CGoods {
public:
CGoods();
CGoods(char *name,double _price,int mount);
CGoods(const CGoods& src);
void operator = (const CGoods& src);
~CGoods();
private:
char *_pname;
double _price;
int _mount;
};
#endif //C_CGOODS_H
CGoods.cpp
#if 0
#include <iostream>
#include "CGoods.h"
using namespace std;
CGoods::CGoods()
{
cout<<"CGoods"<<endl;
_pname = new char[1];
_pname[0] = '\0';
}
CGoods::CGoods(char *name,double price,int mount)
{
cout<<"CGoods(char *, double, int)"<<endl;
_pname = new char[strlen(name)];
strcpy(_pname,name);
_price = price;
_mount = mount;
}
CGoods::CGoods(const CGoods& src)
{
cout<<&src << "---->" << this <<endl;
cout<<"拷贝构造函数"<<endl;
_pname = new char[strlen(src._pname)+1];
strcpy(_pname,src._pname);
_mount = src._mount;
_price = src._price;
}
/*没有考虑异常安全的赋值重载函数*/
#if 0
CGoods& CGoods::operator=(const CGoods &src)
{
cout<<&src << "---->" << this <<endl;
cout<<"CGoods operator="<<endl;
if(this == &src)
return *this;
delete []_pname;
_pname = NULL;
_pname = new char[strlen(src._pname)+1];
strcpy(_pname,src._pname);
_mount = src._mount;
_price = src._price;
return *this;
}
#endif
/*考虑异常安全的赋值重载函数*/
//写法一:先申请内存,new成功后在释放_pname指向堆上的资源
//写法二:创造一个临时对象,在交换临时对象和原来的类(会多调用一次拷贝构造函数)
#if 1
CGoods& CGoods::operator=(const CGoods &src)
{
cout<<&src << "---->" << this <<endl;
cout<<"CGoods operator="<<endl;
if(this != &src)
{
CGoods goodsTemp(src);
char *pTemp = goodsTemp._pname;
goodsTemp._pname = _pname;
_pname = pTemp;
_mount = src._mount;
_price = src._price;
}
return *this;
}
#endif
CGoods::~CGoods()
{
cout<<"~CGoods"<<endl;
delete []_pname;
_pname = NULL;
}
int main()
{
CGoods goods1;
CGoods goods2("apple",3.5,6);
CGoods goods3;
goods3 = goods1;
// goods3 = goods2;
// CGoods goods4;
// goods4 = goods3 = goods2;
return 0;
}
#endif
运行结果:
CGoods
CGoods(char *, double, int)
0x7fff52731b40---->0x7fff52731b00
拷贝构造函数
0x7fff52731b00---->0x7fff52731b00
CGoods operator=
~CGoods
~CGoods
~CGoods
分析总结:在自己定义的拷贝构造函数中
- 当申请了外部资源时,为了防止浅拷贝,我们应该为该对象申请属于自己的外部资源,否则src引用的对象析构后,释放了外部资源,新对象再去释放相同的堆上的资源就会引起程序放生崩溃!
- 拷贝构造函数的形参应传递引用,如果进行值传递会发生递归调用自身(拷贝构造函数),函数栈会益处。
分析总结:在实现的赋值运算重载函数中
- 防止内存泄漏,要先将该对象在堆上的外部资源释放后,将指针置成NULL,在进行资源赋值;
- 当申请了外部资源时,为了防止浅拷贝,我们应该为该对象申请属于自己的外部资源,否则src引用的对象析构后,释放了外部资源,新对象再去释放相同的堆上的资源就会引起程序放生崩溃!
- 拷贝构造函数的形参应传递引用,如果进行值传递会发生递归调用自身(拷贝构造函数),函数栈会益处。
- 为了防止自赋值,写代码时手抖了,自身赋值给自身,当对一个空指针strlen的时候会程序会崩溃,因为在虚拟地址空间中前128个字节不能访问,所以我们要防止自赋值发生。