3.【CPP入门】(深浅拷贝||运算符重载||赋值运算符重载)

一.浅拷贝和深拷贝

1.引入

从上篇博客拷贝构造我们知道拷贝构造要传引用而不能传值,否则会发生无穷递归的情况。

1.若未显示定义拷贝构造函数,系统会生成默认的拷贝构造函数。默认的拷贝构造按内存序完成拷贝,我们称之为浅拷贝(值拷贝)。注:对内置类型按照字节方式拷贝,而自定义类型调用其的拷贝构造函数。
2.浅拷贝就是新拷贝的对象和原对象指向同一块空间,新拷贝的对象的值的改变也会引发原对象的值的改变。
3.深拷贝实质是在内存里重新为新拷贝的对象开辟一块空间,不指向同一块空间。

2.问题

我们拷贝日期这样的类用浅拷贝是没问题的,年月日都是在栈上创建销毁由系统开空间的释放空间的,但是如果这样的类呢?


class String
{
public:
	String(const char* str = "jack")
	{
		_str = (char*)malloc(strlen(str) + 1);
		strcpy(_str, str);
	}
	~String()
	{
		cout << "~String()" << endl;
		free(_str);
	}
private:
	char* _str;
};
int main()
{
	String s1("hello");
	String s2(s1);
}

_str是我们malloc出来在堆上的空间需要我们自己调用析构free掉,s2拷贝构造s1,编译器自动生成的默认拷贝函数会使s2和s1指向同一块空间,先定义的对象先析构,s1先析构掉这块开好的空间,s2再次析构时这块空间已经被释放掉了,程序报错。

二.运算符重载

1.概念

C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,也具有其返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似

函数名字为:关键字operator后面接需要重载的运算符符号。
函数原型:返回值类型 operator操作符(参数列表)

不能通过连接其他符号来创建新的操作符:比如operator@
重载操作符必须有一个类类型参数
用于内置类型的运算符,其含义不能改变,例如:内置的整型+,不 能改变其含义
作为类成员函数重载时,其形参看起来比操作数数目少1,因为成员函数的第一个参数为隐藏的this
.* :: sizeof ?: . 注意以上5个运算符不能重载。这个经常在笔试选择题中出现。

例如:以下在.h中声明,再cpp中实现的>运算符

bool Date::operator>(const Date& d)const
{
	return (_year > d._year)
		|| ((_year == d._year) && (_month > d._month))
		|| (_year == d._year) && (_month == d._month) && (_day > d._day);
}

写一个>和==就足够了,剩下的代码复用就行.

2.赋值运算符重载

2.1注意:

赋值运算符主要注意以下几点

1.参数类型:const T&,传递引用可以提高传参效率
2.返回值类型:T&,返回引用可以提高返回的效率,有返回值目的是为了支持连续赋值
3.检测是否自己给自己赋值
4.返回*this :要符合连续赋值的含义

//d1=d3
	Date& operator=(const Date& d)//引用作返回值,不用调用拷贝构造存临时变量
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
		return *this;
	}
2.2 赋值运算符只能重载成类的成员函数不能重载成全局函数

原因:赋值运算符如果不显式实现,编译器会生成一个默认的。此时用户再在类外自己实现一个全局的赋值运算符重载,就和编译器在类中生成的默认赋值运算符重载冲突了,故赋值运算符重载只能是类的成员数。
用户没有显式实现时,编译器会生成一个默认赋值运算符重载,以值的方式逐字节拷贝。注意:内置类型成员变量是直接赋值的,而自定义类型成员变量需要调用对应类的赋值运算符重载完成赋值。

2.3涉及资源管理避免默认生成的拷贝构造

同上浅拷贝和深拷贝的问题

3. 前置++和后置++的运算符重载

Date& Date::operator++(int)
{
	Date ret(*this);
	*this += 1;

	return ret;
}
Date& Date::operator++()
{
	*this += 1;
	return *this;
}

前置++先加加后使用,后置++先使用再加加,为了区分C++规定:后置++重载时多增加一个int类型的参数,但调用函数时该参数不用传递,编译器自动传递。

你可能感兴趣的:(c++,开发语言)