3-5:类与对象中篇——默认成员函数之运算符重载

Posted 快乐江湖

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了3-5:类与对象中篇——默认成员函数之运算符重载相关的知识,希望对你有一定的参考价值。

一:运算符重载

(1)运算符重载

A:为什么要有运算符重载?

如下,我们定义一个整形变量i,对他进行一些运算符操作,比如加减乘除,这一点是大家很熟悉的,并且编译也直到该怎么做。

int main()
{
	int i=1;
	i+1;//编译器知道这样做的意义
	i*2;//编译器知道这样做的意义
}

但是,对于自定义类型就不是这样了。比如用前面的日期类,去实例化一个对象,如果你拿上这个对象进行上述的操作,编译就不知道你这样做的意义何在。

int main()`在这里插入代码片`
{
	Date d;
	d+1;//编译器不知道这里是什么意思,或许是加一天?加一个月?还是其他意思
	d*2;//这种操作显然不合理。
}

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

上面d+1是有意义的,所以我们可以重载+d*2是没有意义的,所以就不要重载*

B:如何进行运算符重载

运算符重载是具有特殊函数名的函数:

  • 函数名:operator接 【需要重载的运算符符号】
  • 函数原型为:【返回值类型】【operator】【操作符】【参数列表】

特别注意一下几点:

  • 连接的操作符必须是已有的,不能自己去创造新的操作,比如就没有@这样的操作符,所以不能写成operator@
  • 重载操作符针对的是自定义类型
  • 作为类成员的重载函数时,其形参看起来比操作数数目少1一个成员,因为有一个默认的this指针
  • .*::sizeof?:.,这五个运算符不能重载

用于重载运算符的函数可以放在类之外,也可以放在类内
如果放在类之外(以日期类为例),这里我的目的是比较两个日期类对象的大小,看其是否相等,如下,对于自定义类型直接使用d1==d2显然是不对的,所以写运算符重载函数如下

class Date
{
public:
	Date(int year=2000, int month=1, int day=1)
	{
		std::cout << "调用了构造函数" << std::endl;
		_year = year;
		_month = month;
		_day = day;
	}

	void DisPlay()
	{
		std::cout << _year << "-" << _month << "-" << _day << std::endl;
	}
private:
	int _year;
	int _month;
	int _day;
};

bool operator==(Date& d1,Date& d2)//运算符重载函数
{
	return d1._year==d2.year
	&&d1.month==d2.month
	&&d3.day=d3.day;

}
int main()
{
	Date d1(2002, 2, 2);
	Date d2(d1);

	d2.DisPlay();
	d1.DisPlay();

	if(d1==d2)//运算符已经被重载了,所以可以直接使用
	//d1==d2等价于operater==(d1,d2)
		std::cout<<"相等"<<std::endl;
	return 0;
}

这种写法实则是有问题的,运算符重载函数写在类之外,而类内成员变量都是私有的,也就是外部访问是非法的。当然解决这个问题的方法也很多,比如在类内写一个可以返回成员变量的函数,但是这种写法很麻烦。

如果将其放在类之内呢?
在这里插入图片描述
这里报出的错误是说“参数太多”。其实出现这个问题原因就是上面注意事项中说到的第三条,作为类成员的重载函数时,其形参看起来比操作数数目少1一个成员,因为有一个默认的this指针。调用成员函数时,d1.operatror已经有一个默认的this指针指向它了,那么在函数形参里其实第一个位置已经默认放了d1了,所以形参中只需放入d2即可
在这里插入图片描述

(2)赋值运算符重载

=是赋值号,它的重载有一些需要注意的地方。首先这里要区别拷贝构造,拷贝构造相当于是这种形式

int main()
{
	int a=1;
	int b=a;//Date d2(d1)    Date d2=d1;

}

而这里说的运算符重载指的是这样

int main()
{
	int a=1;
	int b=2;
	a=b;
}

根据上文说到的运算符重载,所以可以写出赋值运算符的重载如下
在这里插入图片描述
为了表面出现类似d1=d1的操作,修改赋值运算符重载函数如下

Date& operator=(Date& d)
{
	if(this!=&d)//由于this是指针,所以对d要取地址
	{
		_year=d.year;
		_month=d.month;
		_day=d.day;
	}
	return *this;


}

当然拷贝构造和赋值运算符重载很类似,拷贝构造前文说过如果不写编译器默认生成的也会按照浅拷贝的方式按照字节序进行拷贝,那么赋值运算符重载呢?答案也是可以的
在这里插入图片描述
错题
在这里插入图片描述
在这里插入图片描述

二:const修饰类的成员函数

下面的代码,能够正常运行时肯定的
在这里插入图片描述
但是如果我在初始化是写成const Date d1(2000,1,1),则会出现以下错误
在这里插入图片描述
实际开发中经常用这样的例子,如下面这样,使用实例化的对象传参,形参是一个引用,为了进行保护,一般会使用const修饰

void fun(const Date& d)
{
	d.print();
}
int main()
{
	Date d1(2000,1,1);
	fun(d1);
}

这样一来,函数内传入d1,形参使用const修饰,权限缩小,调用其成员函数时,print()里默认有一个this指针,其类型是Date*的,而不是const Date*的,这样一来权限被扩大,因此会报错

那么是否可以把它的形参改为const Date*呢?显然不可以,因为thisi指针是隐含的,如果这样硬是写入,那么相当于最后是两个参数了。
所以为了解决这个问题,在C++中,要是使用const修饰类的成员函数的话,直接在函数后面加上const

在这里插入图片描述

  • 还是那句话,权限只可以缩小,不能够放大。也就是我本身只能是可读的(const),不能传过去编程可读可写的了(非const)

以上是关于3-5:类与对象中篇——默认成员函数之运算符重载的主要内容,如果未能解决你的问题,请参考以下文章

类与对象(中篇)

C++从入门到入土第四篇:类与对象(中篇)

3-3:类与对象中篇——默认成员函数之构造函数和析构函数

C++类和对象(中篇)

C++基础三类和对象(中篇)

C++基础三类和对象(中篇)