C++运算符重载

发布于:2024-09-18 ⋅ 阅读:(14) ⋅ 点赞:(0)

一、运算符重载

1、规定
  • C++允许我们对类类型使用运算符,但要我们自己通过运算符重载完成类类型的运算,如果没有对应的运算符重载就会报错。
  • 运算符重载需要使用特殊关键词operator后跟运算符来完成定义。它跟函数写法一样,具有返回值,函数参数类型,和函数体。
  • 运算符重载不会改变运算符的优先级和结合性。
  • 运算符重载不能重载C++里没有规定的符号,但 .* :: sizeof ?: . 这五个运算符不能重载。

.* 运算符的作用,用于定义类的成员函数指针

//类成员函数指针
#include <iostream>
using namespace std;

class A
{
public:
	void fun()
	{
		cout << "A::fun" << endl;
	}
};

typedef void(A::*PF)();
int main()
{
	void(A::*pf)();
	pf = &A::fun;
	PF p = &A::fun;
	//调用类函数要先创建一个对象
	A a;
	//然后调用函数指针用.*
	(a.*pf)();
	return 0;
}
2、operator关键词的使用

对于类类型的使用运算符编译器是不知道要干嘛的就需要自己写函数,自己实现功能。

就比如日期类的大小比较。

在这里插入图片描述


多少天后日期是多少

	//返回每该月有多少天
	int GetMonthDay()
	{
		static int  arr[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
		if (_month == 2 && (_year % 4 == 0 && _year % 100 != 0 || _year%400==0))
		{
			return 29;
		}
		return arr[_month];
	}

	Date operator+=(int day)
	{
		_day += day;
		while (_day > (this->GetMonthDay()))
		{
			_day -= this->GetMonthDay();
			_month++;
			if (_month >= 13)
			{
				_year++;
				_month = 1;
			}
		}
		return *this;
	}

判断日期是否相等

bool operator==(const Date& d)
{
	return (_year == d._year && _month == d._month && _day == d._day);
}
  • 前置operator++ 和 后置operator++

编译器会做特殊处理,后置++会多个int类型的形参

	//前置++
	//出了作用域值还在,用引用返回可以减少拷贝
	Date& operator++()
	{
		_day++;
		if (_day > this->GetMonthDay())
		{
			_day -= this->GetMonthDay();
			_month++;
			if (_month > 12)
			{
				_year++;
				_month = 1;
			}
		}
		return *this;
	}

	//后置++
	Date operator++(int i)
	{
		Date tmp = *this;
		_day++;
		if (_day > this->GetMonthDay())
		{
			_day -= this->GetMonthDay();
			_month++;
			if (_month > 12)
			{
				_year++;
				_month = 1;
			}
		}
		return tmp;
	}

二、赋值运算符的重载

1、功能
  • 对两个已经存在的类的对象进行赋值拷贝操作。

  • 要跟拷贝构造区分,拷贝构造是一个已经存在,给另一个初始化时进行的拷贝操作。

  • 如果不写赋值运算符重载函数,系统会自动生成,但是浅拷贝,一个字节一个字节的拷贝,对于占用资源的还是要自己写才好。

  • 支持连续赋值,所以返回值就是类类型本身。

	//赋值运算符重载
	Date& operator=(const Date& d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;

		return *this;
	}

总结如果显示写了析构,就要显示写赋值运算符重载。

2、使用

日期类比较大小

#include <iostream>
#include <stdbool.h>

class Date
{
public:
	Date(int year = 1, int month = 1, int day = 1);

	bool operator <(const Date& d);
	bool operator >(const Date& d);
	bool operator <=(const Date& d);
	bool operator >=(const Date& d);
	bool operator ==(const Date& d);
	bool operator !=(const Date& d);

private:
	int _year;
	int _month;
	int _day;
};

Date::Date(int year, int month, int day)
{
	_year = year;
	_month = month;
	_day = day;
}

bool Date::operator <(const Date& d)
{
	if (_year < d._year)
	{
		return true;
	}
	else if (_year == d._year && _month < d._month)
	{
		return true;
	}
	else if (_year == d._year && _month < d._month && _day < d._day)
	{
		return true;
	}
	return false;
}
bool Date:: operator >(const Date& d)
{
	return !(*this < d || *this == d);
}
bool Date::operator <=(const Date& d)
{
	return (*this < d || *this == d);
}
bool Date::operator >=(const Date& d)
{
	return !(*this < d);
}
bool Date::operator ==(const Date& d)
{
	return _year == d._year && _month == d._month && _day == d._day;
}
bool Date::operator !=(const Date& d)
{
	return !(*this == d);
}

日期 - 日期,日期 + 天数,日期 - 天数,这些都是有意义的

int Date::operator-(const Date& d)
{
	int sum = 0;
	if (*this > d)
	{
		if (d._year < _year)
		{
			for (int i = d._year + 1; i < _year; i++)
			{
				if ((i % 4 == 0 && i % 100 != 0) || i % 400 == 0)
				{
					sum += 366;
				}
				else
				{
					sum += 365;
				}
			}
		
		
			for (int i = d._month + 1; i <= 12; i++)
			{
				sum += GetMonthDay(d._year, i);
			}
			sum += (GetMonthDay(d._year, d._month) - d._day);

			for (int i = 1; i < _month; i++)
			{
				sum += GetMonthDay(_year, i);
			}
		}
		else if(d._year == _year)
		{
			if(d._month == _month)
				sum -= d._day;
			else
			{
				for (int i = d._month+1; i < _month; i++)
				{
					sum += GetMonthDay(_year, i);
				}
				sum += (GetMonthDay(d._year, d._month) - d._day);
			}
			
		}
		
		
		sum += _day;
	}
	else
	{
		if (_year < d._year)
		{
			for (int i = _year + 1; i < d._year; i++)
			{
				if ((i % 4 == 0 && i % 100 != 0) || i % 400 == 0)
				{
					sum -= 366;
				}
				else
				{
					sum -= 365;
				}
			}


			for (int i = _month + 1; i <= 12; i++)
			{
				sum -= GetMonthDay(_year, i);
			}
			sum -= (GetMonthDay(_year, _month) - _day);

			for (int i = 1; i < d._month; i++)
			{
				sum -= GetMonthDay(d._year, i);
			}
		}
		else if (d._year == _year)
		{
			if (d._month == _month)
				sum += _day;
			else
			{
				for (int i = _month+1; i < d._month; i++)
				{
					sum -= GetMonthDay(_year, i);
				}
				sum -= (GetMonthDay(_year, _month) - _day);
			}

		}


		sum -= d._day;
	}
	return sum;
}


Date& Date::operator+=(const int day)
{
	if (day < 0)
	{
		return *this -= -day;
	}
	_day += day;
	while (_day > GetMonthDay(_year, _month))
	{
		_day -= GetMonthDay(_year, _month);
		_month++;
		if (_month >= 13)
		{
			_year++;
			_month = 1;
		}
	}
	return *this;
}

Date Date::operator+(const int day)
{
	Date tmp = *this;
	tmp += day;
	return tmp;
}

Date& Date::operator-=(const int day)
{
	if (day < 0)
	{
		return *this += -day;
	}
	_day -= day;
	while (_day <= 0)
	{
		_day += GetMonthDay(_year, _month);
		_month--;
		if (_month <= 0)
		{
			_year--;
			_month = 12;
		}
	}
	return *this;
}
Date Date::operator-(const int day)
{
	Date tmp = *this;
	tmp -= day;
	return tmp;
}

输入(流提取)>>,输出(流插入)<< 运算符

	//友元声明
	friend ostream& operator<<(ostream& out, const Date& d);
ostream& operator<<(ostream& out, const Date& d)
{
	out << d._year << "年" << d._month << "月" << d._day << "日" << endl;
	return out;
}

三、取地址运算符重载

1、const修饰成员函数

让成员函数的第一个隐含的this的指针指向的内容不被修改
应为this不能出现在形参和实参中所以加const的方式也不同,加在函数定义的后面,表示给
this加上了const
格式如下:

class Date
{
public:
	void Print() const//在定义的后面加,表示隐含的tist所指向的内容不能被修改
	{
		std::cout << _year << "年" << _month << "月" << _day << "日" << std::endl;
	}

private:
	int _year;
	int _month;
	int _day;
};
//相当于把 Date* const this变成了const Date* const this;

加const有好处可以避免权限放大
但也牺牲了些东西就是不能修改内容,但需要修改内容是可以写两个版本的成员函数,因为支持函数重载,系统会选择最适合的成员函数调用

2、取地址运算符重载

对类类型进行取地址时按理来说,自定义类型想要使用运算符都需要自己重载,但取地址运算符,编译器会自动生成默认成员函数。
编译器自动生成如下函数重载:

	Date* operator&()
	{
		return this;
	}

	const Date* operator&()const
	{
		return this;
	}

编译器会执行最匹配的那一个,一般不需要自己写。
除非不需让别人获取到类对象的地址。


网站公告

今日签到

点亮在社区的每一天
去签到