1、作用
这是我们拷贝构造函数的代码
class CGoods
{
public:
//拷贝构造函数
CGoods(const CGoods& rhs)
{
cout << this << ":CGoods::CGoods(CGoods )" << endl;
_name = new char[strlen(rhs._name) + 1]();
strcpy(_name, rhs._name);
_price = rhs._price;
_amount = rhs._amount;
}
CGoods(char* name, float price, int amount)
{
cout << this << ":CGoods::CGoods(char* , float , int )" << endl;
_name = new char[strlen(name) + 1]();
strcpy(_name, name);
_price = price;
_amount = amount;
}
//析构函数
~CGoods()
{
cout << this << ":~CGoods()" << endl;
delete[] _name;
_name = NULL;
}
private:
char* _name;
float _price;
int _amount;
};
int main()
{
CGoods good1("good1", 500, 10);
CGoods good2 = good1;
return 0;
}
(2)如果我们在调用点添加下面两行代码,我们会认为是给 good1 重新赋值,运行是可以通过的,但是编译器并不知道自定义类型它是如何进行赋值的。
CGoods good3;
good3 = good2;
(3)针对上面的问题我们用赋值运算符重载函数,它的作用是用一个已存在的对象给另一个已存在的对象赋值。
2、特征
(1)有返回值,返回值是类类型的引用
(2)有自赋值的判断
它是为了避免有good2 = good2;`的存在,它是符合语法语义的,但是无意义,所以判断自赋值。
也就是判断 this 指针所指向的对象是不是与 rhs 相同的地址。
CGoods& operator = (const CGoods& rhs)
{
if (this == &rhs)
{
return *this;
}
_name = rhs._name;
_price = rhs._price;
_amount = rhs._amount;
return *this;
}
- 浅拷贝
但是程序崩溃了,这与拷贝构造函数的问题一样,是进行了浅拷贝,出现了野指针导致的函数崩溃。
可以参考 拷贝构造函数 - 深拷贝
不能直接赋值,如果原本的对象已经有开辟的堆内存,如果直接赋值会导致原对象的堆内存找到指向,导致内存泄漏。
所以应该先释放原对象的内存,再开辟新内存。
CGoods& operator=(const CGoods& rhs)
{
if (this != &rhs)
{
delete[] _name;
_name = new char[strlen(rhs._name) + 1];
strcpy(_name, rhs._name);
_price = rhs._price;
_amount = rhs._amount;
}
return *this;
}
3、临时对象
如果在调用点写一个这样的语句good3 = "good3";
,我们认为它是无法运行的,因为前者是 CGoods 类型,后者是 char* 类型,两者类型不匹配。但是如果在类中有一个只有char类型参数的构造函数,能运行成功,为什么???
我们可以认为是用char类型生成了一个临时对象后,使两者类型相同,然后再调用赋值运算符函数进行赋值。
所以临时对象的生存周期是在本条语句结束时就调用析构函数,释放内存。
class CGoods
{
public:
CGoods()
{
cout << this << ":CGoods::CGoods()" << endl;
}
//拷贝构造函数
CGoods(const CGoods& rhs)
{
cout << this << ":CGoods::CGoods(CGoods )" << endl;
_name = new char[strlen(rhs._name) + 1]();
strcpy(_name, rhs._name);
_price = rhs._price;
_amount = rhs._amount;
}
CGoods(char* name, float price, int amount)
{
cout << this << ":CGoods::CGoods(char* , float , int )" << endl;
_name = new char[strlen(name) + 1]();
strcpy(_name, name);
_price = price;
_amount = amount;
}
//赋值运算符重载函数
CGoods& operator=(const CGoods& rhs)
{
cout << this << ":CGoods::operator = (CGoods)" << endl;
if (this != &rhs)
{
delete[] _name;
_name = new char[strlen(rhs._name) + 1];
strcpy(_name, rhs._name);
_price = rhs._price;
_amount = rhs._amount;
}
return *this;
}
CGoods(char* name)
{
cout << this << ":CGoods::CGoods(char*)" << endl;
_name = new char[strlen(name) + 1]();
strcpy(_name, name);
}
//析构函数
~CGoods()
{
cout << this << ":~CGoods()" << endl;
delete[] _name;
_name = NULL;
}
private:
char* _name;
float _price;
int _amount;
};
int main()
{
CGoods good1("good1", 500, 10);
CGoods good2 = good1;
CGoods good3;
good1 = good2;
cout << "-----------------------" << endl;
good3 = "good3";
cout << "-----------------------" << endl;
return 0;
}
4、临时量
(1)内置类型(基本类型)产生的临时量是常量,存放在存储器中。
(2)自定义类型产生的临时量为变量,存放在内存中。
(3)隐式生成的临时量是常量,不能用普通引用来引用一个常量对象。
也就是实现good3 = "good3";
时必须调用参数中带有const 的引用。
(4)显式生成的临时量是变量,可以用普通引用来引用。
也就是写成实现good3 = CGoods("good3");
,就可以调用参数中没有const 的引用。