C++ 类与对象(二)(2.运算符重载)

目录

赋值运算符重载

1.运算符重载

2.赋值运算符重载

3.日期类实现

取地址运算符重载

[1.const 成员](#1.const 成员)

2.取地址运算符重载


运算符重构(operator)

运算符重构是对类这和算符的适配性进行一个适配的重构,就是对于平常的运算符无法进行加减乘除等等还有赋值操作符进行一个新的从新修改。而在C++中就允许我们可以进行对运算符进行从新修改操作,对于运算符重构还需要有一个重要字(operator),在这个关键字的后面直接加上对应的运算符像 ++ -- += -=等等(除了 .* :: sizeo() . ?: )这5个运算符无法修改)。

赋值运算符重载

1.运算符重载

运算符重载的注意点:

1,必须是有一个类相关的传值,如果没有就变成重构原本的运算的意义

cpp 复制代码
//error
int operator+(int a,int b)
{
    return a-b;
}

2,不能重构没有意义的运算符如:operator@

加减运算符重载

正确示范:

以 Date 日期类为例

日期类的 += 运算符重载实现:

cpp 复制代码
/*传年月取月份总天数*/

int Date::GetMonthDay(int year, int month)
{
	//最基础的实现一一对应每个月份的数组传值(为了不浪费一个空间把0位置改为闰年2月份的存储位置)
	static const int month_day[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
    //2月份 闰年的判断
	if (month == 2 && ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0))
	{
		return 29;
	}
	else
	{
		return month_day[month];
	}
}

Date& Date::operator+=(int day)
{
	//判断如果传过来的day 是否为负数如果为负数就给-=处理,注意一定要改day的正负数
    if (day < 0)
	{
		return *this -= -day;
	}
    //先进行加减
	_day += day;
    //修改直到day为正确的日期为止 注意不要>=号会导致出现0号情况
	while (_day > GetMonthDay(_year, _month))
	{
		_day -= GetMonthDay(_year, _month++);
		if (_month == 13)
		{
			_month = 1;
			_year++;
		}
	}
    
	return *this;
}

注意:对应的*this 在函数销毁时*this 的生命周期还在所以可以用类类型的应用进行返回。

日期类的 + 运算符重载实现:

cpp 复制代码
//利用已有的+=实现
Date Date::operator+(int day)
{
	// + 的实现是通过原数值没有更改 所以进行拷贝出来的实例化对象,用这个实例化对象进行+=操作
    Date tmp = *this;
    return tmp += day;
}
  • 的实现是通过原数值没有更改 所以进行拷贝出来的实例化对象,用这个实例化对象进行+=操作

注意:所拷贝出来的对象是一个临时对象,这个不能用Date& 的类类型的引用返回值,只能用类类型即可。

日期类的 -= - 运算符重载实现:

与+= +是同理的

cpp 复制代码
Date& Date::operator-=(int day)
{

	//判断如果传过来的day 是否为负数如果为负数就给+=处理,注意一定要改day的正负数
    if (day < 0)
	{
		return *this += -day;
	}

    //先进行加减
	_day -= day;
    //修改直到day为正确的日期为止 注意这里与+=不同需要<=0,还是那个问题防止出现0号的问题
	while (_day <= 0)
	{
		_day += GetMonthDay(_year, _month--);
		if (_month == 0)
		{
			_month = 12;
			_year--;
		}
	}
	return *this;
}
Date Date::operator-(int day)
{
	// - 的实现是通过原数值没有更改 所以进行拷贝出来的实例化对象,用这个实例化对象进行-=操作
    Date tmp = *this;
	return tmp -= day;
}

注意点:返回值需不需要引用的问题,还是考虑是不是临时对象,传值后会不会消亡

++ -- 的前置后置更改的实现:

在++ 和-- 都有前置与后置问题,但是运算符有时一模一样就没有办法区分,所以C++就进行了一个特殊处理,有传参的运算符就是后置,没有的表示前置,一定要int 只要有传参即可区分。

cpp 复制代码
operator++()//前置
operator++(int)//后置
operator--()//前置
operator--(int)//后置

代码展示:

cpp 复制代码
Date& Date::operator++()//后置
{
	*this += 1;
	return*this;
}
Date& Date::operator++(int)//前置
{
	Date tmp = *this;
	*this += 1;
	return tmp;
}
Date& Date::operator--()//后置
{
	*this -= 1;
	return*this;
}
Date& Date::operator--(int)//前置
{
	Date tmp = *this;
	*this -= 1;
	return tmp;
}

比较运算符重载

== != > >= < <=

cpp 复制代码
bool Date::operator==(const Date& dat) 
{
	return _year == dat._year && _month == dat._month && _day == dat._day;
}
bool Date::operator!=(const Date& dat) 
{
	return !(*this == dat);

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

其实主要实现的**== > <** 这三个其他都是利用了!取反的运算符进行实现的。

练习题:

两个日期相减得出两天之间差距多少天。(答案在日期类实现中)

cpp 复制代码
/*天数相减计算天数*/
int operator-(const Date& date);

2.赋值运算符重载

cpp 复制代码
Date tmp = *this;
Date tmp(*this);

上面的代码都是等效的,这两个代码都是利用拷贝构造函数实现的,但所谓的赋值运算就是比已经实力化对象,进行赋值操作,就得重新对=赋值进行重构操作。

cpp 复制代码
int main()
{
	//实例化拷贝构造
	Date a(2026, 8, 9);
	Date b = a;
	b.Print();
	
	//赋值运算
	Date c(2026, 8, 9);
	Date d;
	d = c;
	d.Print();

	return 0;
}
cpp 复制代码
Date& Date::operator=(const Date& d)
{
	if (*this != d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}

	return *this;
}

建议:在传参加const ,防止误操;返回值要使用类类型的应用,可以支持连续赋值场景

在没有赋值重构的时候编译器自动生成一个赋值传参进行一个字节一个字节的拷贝,支配性可能容易出现环境不适配的问题,Stack 等这种就一定需要赋值重载的情况。

3.日期类实现

cpp 复制代码
/*天数相减计算天数*/(答案不唯一,原理实现即可)
int Date::operator-(const Date& date) 
{
	Date tmp = *this;
	int day = 0, fu = 1;
	if (*this > date)
		fu = -1;
	while (tmp != date)
	{
		day += fu;
		tmp += fu;
	}
	return fu*day;
}
cpp 复制代码
//Data.h
#pragma once
#include <iostream>
#include <stdlib.h>
#include <stdbool.h>
#include <assert.h>

using namespace std;

class Date
{
public:
	Date(int year = 1, int month = 1, int day = 1);//构造函数(缺省)
	Date(Date& date);//拷贝构造函数
	Date(const Date& date);
	void Print();//输出
	int GetMonthDay(int year, int month);//取月天数

	//运算符重载
	/*加减天数改变天数*/
	Date& operator+=(int day);
	Date operator+(int day);
	Date& operator-=(int day);
	Date operator-(int day);

	/*++ -- 的前置后置更改的实现*/
	Date& operator++();//前置
	Date operator++(int);//后置
	Date& operator--();//前置
	Date operator--(int);//后置

	/*比较天数*/
	bool operator==(const Date& dat)const;
	bool operator!=(const Date& dat)const;
	bool operator>(const Date& dat)const;
	bool operator<(const Date& dat)const;
	bool operator>=(const Date& dat)const;
	bool operator<=(const Date& dat)const;

	/*天数相减计算天数*/
	int operator-(const Date& date);

	/*赋值运算符*/
	Date& operator=(const Date& d);
	
	/*取地址运算符重构*/
	Date* operator&();
	const Date* operator&()const;

private:
	int _year;
	int _month;
	int _day;
};
cpp 复制代码
//Data.cpp

#define _CRT_SECURE_NO_WARNINGS

#include "Data.h"
/************************************* 基本的函数 **********************************************/


//构造
Date::Date(int year, int month, int day)
{
	_year = year;
	_month = month;
	_day = day;
}
//拷贝构造
Date::Date(Date& date)
{
	_year = date._year;
	_month = date._month;
	_day = date._day;
}
Date::Date(const Date& date)
{
	_year = date._year;
	_month = date._month;
	_day = date._day;
}
/*传年月取月份总天数*/
int Date::GetMonthDay(int year, int month)
{
	static const int month_day[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;
	}
	else
	{
		return month_day[month];
	}
}
/*输出函数*/
void Date::Print()
{
	cout << _year << "/" << _month << "/" << _day << endl;
}


/********************************** 运算符重载 ***********************************************/

/*加减天数改变天数*/
Date& Date::operator+=(int day)
{
	if (day < 0)
	{
		return *this -= -day;
	}

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

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

/*++ -- 的前置后置更改的实现*/
Date& Date::operator++()//前置
{
	*this += 1;
	return*this;
}
Date Date::operator++(int)//后置
{
	Date tmp = *this;
	*this += 1;
	return tmp;
}
Date& Date::operator--()//前置
{
	*this -= 1;
	return*this;
}
Date Date::operator--(int)//后置
{
	Date tmp = *this;
	*this -= 1;
	return tmp;
}

/*比较天数*/
bool Date::operator==(const Date& dat) const
{
	return _year == dat._year && _month == dat._month && _day == dat._day;
}
bool Date::operator!=(const Date& dat) const
{
	return !(*this == dat);

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

/*天数相减计算天数*/
int Date::operator-(const Date& date) 
{
	Date tmp = *this;
	int day = 0, fu = 1;
	if (*this > date)
		fu = -1;
	while (tmp != date)
	{
		day += fu;
		tmp += (fu);
	}
	return fu*day;
}

/*赋值运算符*/
Date& Date::operator=(const Date& d)
{
	if (*this != d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}

	return *this;
}
/*取地址运算符重构*/
Date* Date::operator&()
{
	return this;
}
const Date* Date::operator&()const
{
	return this;
}


int main()
{

	return 0;
}

取地址运算符重载

1.const 成员

传参参数可以加const ,进行防止误操的情况,但我们 *this 这个时在类里面的我们在调用的时候也可以进行更改,但在用有一些函数的时候我们不需要进行修改 *this 的情况,但想要加const就变成个问题,所以在C++中就提供了一个解决方案,在函数括号后加const 进行限定 *this 。

cpp 复制代码
bool Date::operator==(const Date& dat) const

2.取地址运算符重载

跟地址有关的有 & \[\] 这两个所也可以通过重构进行。

cpp 复制代码
Date* Date::operator&()
{
	return this;
}
const Date* Date::operator&()const
{
	return this;
}
cpp 复制代码
//test.h

class Arr
{
public:
	Arr(int n=4);//构造
	int operator[](int n);
	~Arr();
private:
	int* _arr;
};


//test.cpp

Arr::Arr(int n)
{
	_arr = (int*)malloc(sizeof(int) * n);
	if (_arr == NULL)
	{
		perror("malloc");
		exit(1);
	}
}
int Arr::operator[](int n)
{
	return _arr[n];
}
Arr::~Arr()
{
	free(_arr);
	_arr = NULL;
}

感谢观看!!!

相关推荐
sakiko_3 小时前
OC基础语法(与Swift对比)-1
开发语言·ios·objective-c·swift
迷迭香yy3 小时前
基金档案数据工程实战从收入分析到持仓穿透的Python解析 IG50免费开源股票数据API接口
开发语言·python
晊晌_h4 小时前
嵌入式从0到精通——线程
java·开发语言·jvm
一木 之林4 小时前
五、C++ 新特性、关键字与编译原理(进阶)(二)
java·开发语言·c++
OPEN-F4 小时前
C++11/14新特性精讲:移动语义与智能指针实战
开发语言·c++·算法
小灰灰搞电子4 小时前
Rust+Slint 实现动态轮播图源码分享,支持动态删除、添加
开发语言·rust·slint·动态轮播图
前端 贾公子4 小时前
第09章:上下文与记忆 (6)
开发语言·前端·python
闭月之泪舞4 小时前
C++编程学习
c++·学习
sunburn-5 小时前
Java堆(Heap)详解与实战教学
java·开发语言·数据结构·ide·算法
jayson.h5 小时前
PDF 合并+添加页码 相关库、类、函数
开发语言·前端·python