析构函数/拷贝构造/赋值重载

析构函数:

	//  析构函数
	~Stack()
	{
		_top = 0;
		_capacity = 0;
		free(_a);
		_a = nullptr;
	}

1 、2两点与构造函数类似。

3、当我们未显示定义时,编译器会自动生成默认的析构函数。C++中,对于内置类型不进行任何处理,对于自定义类型,会分别去调用它们的析构函数。

对于Date类,没有动态申请资源,且全是内置类型,编译器不进行任何处理。当然,当对象的生命周期结束后,里面的变量也会销毁。

对于Stack类,有动态申请资源,也有内置类型,无自定义类型。对于动态申请资源的部分,我们需要自己写析构函数,对这些部分进行free,当对象生命周期结束时,编译器自动调用我们写的析构函数,对于申请的空间进行释放。内置部分可以在~Stack中进行清理、置空等。

对于MyQueue类,内部是2个自定义类型的Stack函数,默认析构函数会自动调用Stack的析构函数,从而自动对MyQueue的对象进行资源清理工作。

拷贝构造函数:

默认拷贝构造对于内置类型会进行浅拷贝,对于自定义类型,会去调用它们的拷贝构造函数。

Date类,直接将所有变量进行浅拷贝即可。

MyQueue类,调用2次Stack的拷贝构造,完成对对象的拷贝构造。

对于Stack类,默认拷贝构造只能完成浅拷贝,此时就需要手动写一个 深拷贝构造。

 当Stack是浅拷贝时,两次的_a指针指向同一块空间。在对st2进行析构时,会对这块空间free,当对st1进行析构时,就会对同一块空间多次free,从而产生错误。

要分清 深、浅拷贝之间的区别。

	//  拷贝构造函数
	Stack(const Stack& x)
	{
		_top = x._top;
		_capacity = x._capacity;
		int* tmp = (int*)malloc(sizeof(int) * x._capacity);
		if (nullptr == tmp)
		{
			perror("malloc fail");
			return;
		}
		_a = tmp;
		memcpy(_a, x._a, sizeof(int) * x._top);
	}

拷贝构造函数典型调用场景:
1、使用已存在对象创建新对象
2、函数参数类型为类类型对象
3、函数返回值类型为类类型对象

 返回的值不是引用,且为自定义类型时,都会调用对应的拷贝构造函数。

这里给ret赋值,实际上是初始化操作,因此也需要调用拷贝构造函数。

传参时,由于形参是一份临时拷贝,因此也需要调用拷贝构造。

注意:实现拷贝构造时,参数类型必须是这个类的引用  const Type& x,如果不为引用,则在传参时就会调用拷贝构造,从而引发无限递归调用,发生错误。

运算符重载:

C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,也具有其
返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。
函数名字为:关键字operator后面接需要重载的运算符符号
函数原型:返回值类型 operator操作符(参数列表)。

简单来说:在C语言中,我们对于内置类型可以使用运算符进行有关操作。而在C++中,我们想将这些操作推广到自定义类型中。

而对于不同的自定义类型,可以使用的运算符是不同的,我们可以自己定义几个特殊的函数来实现这些运算符的功能。

注意:

 作为类成员函数(在类的内部进行实现)重载时,其形参看起来比操作数数目少1,因为成员函数的第一个参数为隐藏的this指针。

赋值运算符重载:

1. 赋值运算符重载格式

1、参数类型:const T&,传递引用可以提高传参效率。
2、返回值类型:T&,返回引用可以提高返回的效率,有返回值目的是为了支持连续赋值。     

3、检测是否自己给自己赋值。
4、返回*this :要复合连续赋值的含义。

这里我将定义和声明分离了,因此需要加上Date::来限定是Date类中的赋值运算符重载。 

 d2=d1的连续赋值,返回值是d2作为这个表达式的返回值。

再将整体给d3初始化,这里虽然用了赋值符号=,但其实是初始化,即调用拷贝构造。

2、必须重载为成员函数

赋值运算符只能重载成类的成员函数不能重载成全局函数。
原因:用户没有在类内部显式实现时,编译器会生成一个默认赋值运算符重载。

如果此时用户再在类外自己实现一个全局的赋值运算符重载,就和编译器在类中生成的默认赋值运算符重载冲突了,故赋值运算符重载只能是类的成员函数。

3、默认赋值重载的特点

用户没有显式实现时,编译器会生成一个默认赋值运算符重载,以值的方式逐字节拷贝。注
意:内置类型成员变量是直接赋值的,而自定义类型成员变量需要调用对应类的赋值运算符
重载完成赋值。

如果像Stack那样需要深拷贝的,则需要自己实现。

+=不用拷贝,+需要拷贝2次

因此复用时,+的内部复用+= 效率更高

 

 函数重载:同名函数,用不同参数来区分。

运算符重载:使得自定义类型也能使用操作符完成相应的操作。

两个重载用了同一个名词,但实际意义不同。

同时,运算符重载时会调用函数,这些运算符重载的函数也可以构成函数重载

这里为了区分前置和后置++,传入一个int类型的参数来区分(因为这个参数没有实际意义,可以只写int这个类型,不写形参名i)

 

目录

析构函数:

拷贝构造函数:

运算符重载:

赋值运算符重载:

1. 赋值运算符重载格式

2、必须重载为成员函数

3、默认赋值重载的特点


  • 12
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 10
    评论
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值