学习笔记(C++篇)--- Day 4

目录

1.赋值运算符重载

[1.1 运算符重载](#1.1 运算符重载)

[1.2 赋值运算符重载](#1.2 赋值运算符重载)

[1.3 日期类实现](#1.3 日期类实现)


1.赋值运算符重载

1.1 运算符重载

①当运算符被用于类类型的对象时,C++语言允许我们通过通过运算符重载的形式指定新的含义。C++规定类类型对象使用运算符时,必须转换成调用对应运算符重载,若没有对应的运算符重载,则会编译报错。

②运算符重载是具有特殊名字的函数,他的名字是由 operator和后面要定义的运算符共同构成。和其他函数一样,它也具有其返回类型和参数列表以及函数体。

③重载运算符函数的参数个数和该运算符作用的运算对象数量一样多。一元运算符有一个参数,二元运算符有两个参数,二元运算符的左侧运算对象传给第一个参数,右侧运算对象传给第二个参数。

④如果一个重载运算符函数是成员函数,则它的第一个运算对象默认传给隐式的 this指针,因此运算符重载作为成员函数时,参数比运算对象少一个。

⑤运算符重载以后,其优先级和结合性与对应的内置类型运算符保持一致。

⑥不能通过连接语法中没有的符号来创建新的操作符:比如 operator@

⑦**.* :: sizeof ?: .** 注意以上5个运算符不能重载。

⑧重载操作符至少有一个类类型参数,不能通过运算符重载改变内置类型对象的含义,如: int operator+(int x, int y)

⑨一个类需要重载哪些运算符,是看哪些运算符重载后有意义;重载++运算符时,有前置++和后置++,运算符重载函数名都是 operator++ ,无法很好的区分。C++规定,后置++重载时,增加一个 int 形参,跟前置++构成函数重载,方便区分。

⑩重载 <<>> 时,需要重载为全局函数,因为重载为成员函数,this 指针默认抢占了第一个形参位置,第一个形参位置是左侧运算对象,调用时就变成了 对象 <<cout ,不符合使用习惯和可读性。重载为全局函数把ostream/istream放到第一个形参位置就可以了,第二个形参位置当类类型对象。

Date比较大小的代码示例:

cpp 复制代码
class Date {
public:
	Date(int year = 1, int month = 1, int day = 1) {
		_year = year;
		_month = month;
		_day = day;
	}

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

bool operator<(const Date& x1, const Date& x2)
{
	if (x1._year < x2._year)
	{
		return true;
	}
	else if (x1._year == x2._year && x1._month < x2._month)
	{
		return true;
	}
	else if (x1._year == x2._year
		&& x1._month == x2._month
		&& x1._day == x2._day)
	{
		return true;
	}
	return false;
}

int main()
{
	Date d1(2024, 8, 9);
	Date d2(2024, 8, 10);
    //bool ret2 = d1 < d2;
    bool ret2 = operator<(d1, d2);
	return 0;
}

1.2 赋值运算符重载

赋值运算符重载是一个默认成员函数,用于完成两个已经存在的对象直接的拷贝赋值,

这里要注意跟拷贝构造区分,拷贝构造用于一个对象拷贝初始化给另一个要创建的对象。

如以下的例子:

cpp 复制代码
int main()
{
	Date d1(2024, 8, 10);
	Date d2(d1);
	Date d3(2024, 9, 11);
	Date d4 = d1;//拷贝构造
	d1 = d3;	 //赋值运算符重载

	return 0;
}

特点:

①赋值运算符重载是一个运算符重载,规定必须重载为成员函数

赋值运算符重载的参数建议写成 const 当前类类型引用,否则会传值传参会有拷贝。

②有返回值,且建议写成当前类类型引用,引用返回可以提高效率,有返回值是为了支持连续赋值场景。

③没有显式实现时,编译器会自动生成一个默认赋值运算符重载,默认赋值运算符重载行为跟默认拷贝函数类似。(栈需要自己实现深拷贝)

DateMyQueue 不需要进行赋值运算符重载,Stack需要进行赋值运算符重载。

(①构造一般需要自己写,自己传参定义初始化;

②析构,构造时有资源申请(如 malloc 或者 fopen)等,就需要显示写析构函数;

③拷贝构造和赋值重载,显示写了析构,内部管理资源,就需要显示实现拷贝构造;)

②的示例如下,这样就支持了连续赋值。

cpp 复制代码
Date& operator = (const Date& d)
{
	_year = d._year;
	_month = d._month;
	_day = d._day;

	return *this;
}

int main()
{
    d1 = d2 = d3;
    return 0;
}

为了防止自己给自己赋值,会进行以下的代码修改:

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

对于③,上述的代码屏蔽之后,我们会发现,代码依旧会正常运行。

1.3 日期类实现

Date.h中的内容:

cpp 复制代码
#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<assert.h>
using namespace std;


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

	int GetMonthDay(int year, int month)
	{
		assert(month > 0 && month < 13);
		static int monthDayArray[13] = { -1, 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 monthDayArray[month];
	}

	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);

	// d1 += 天数
	Date& operator+=(int day);
	Date operator+(int day);
	// d1 -= 天数
	Date& operator-=(int day);
	Date operator-(int day);

	//++d1
	Date& operator++();
	//d1++
	Date operator++(int);

	//日期减去日期
	int operator-(const Date& d);
private:
	int _year;
	int _month;
	int _day;
};

Date.cpp中的内容:

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include"Date.h"

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

void Date::Print()
{
	cout << _year << "-" << _month << "-" << "_day" << endl;
}

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);
}
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);
}
//这种不推荐,推荐下面的方法
//Date Date::operator+(int day)
//{
//	Date tmp = *this;
//	tmp._day += day;
//	while (tmp._day > GetMonthDay(tmp._year, tmp._month))
//	{
//		tmp._day -= GetMonthDay(tmp._year, tmp._month);
//		++tmp._month;
//		if (tmp._month == 13)
//		{
//			tmp._year++;
//			tmp._month = 1;
//		}
//	}
//
//	return tmp;
//}
//
//Date& Date::operator+=(int day)
//{
//	*this = *this + day;
//	return *this;
//}

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

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

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

//++d1
Date& Date::operator++()
{
	*this += 1;
	return *this;
}
//d1++
Date Date::operator++(int)
{
	Date tmp(*this);
	*this += 1;
	return tmp;//后置返回++以前的值
}

int Date::operator-(const Date& d)
{
	Date max = *this;
    Date min = d;
    int flag = 1;
    if (*this < d)
    {
        max = d;
        min = *this;
        flag = -1;
    }
    int n = 0;
    while (min != max)
    {
        ++min;
        ++n;
    }
    return n * flag;
}
相关推荐
饮浊酒10 小时前
Python学习-----小游戏之人生重开模拟器(普通版)
python·学习·游戏程序
li星野10 小时前
打工人日报#20251011
笔记·程序人生·fpga开发·学习方法
摇滚侠10 小时前
Spring Boot 3零基础教程,yml配置文件,笔记13
spring boot·redis·笔记
QT 小鲜肉10 小时前
【个人成长笔记】在Ubuntu中的Linux系统安装 anaconda 及其相关终端命令行
linux·笔记·深度学习·学习·ubuntu·学习方法
QT 小鲜肉10 小时前
【个人成长笔记】在Ubuntu中的Linux系统安装实验室WIFI驱动安装(Driver for Linux RTL8188GU)
linux·笔记·学习·ubuntu·学习方法
急急黄豆10 小时前
MADDPG学习笔记
笔记·学习
BullSmall11 小时前
《道德经》第十七章
学习
Chloeis Syntax11 小时前
栈和队列笔记2025-10-12
java·数据结构·笔记·
知识分享小能手11 小时前
微信小程序入门学习教程,从入门到精通,项目实战:美妆商城小程序 —— 知识点详解与案例代码 (18)
前端·学习·react.js·微信小程序·小程序·vue·前端技术
情深不寿31712 小时前
C++特殊类的设计
开发语言·c++·单例模式