当前位置:网站首页>类和对象(中下)
类和对象(中下)
2022-08-03 12:30:00 【Hey pear!】
5.赋值运算符重载
5.1 运算符重载
C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,也具有其返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。
函数名字
为:关键字operator后面接需要重载的运算符符号。
函数原型
:返回值类型 operator操作符(参数列表)
注意
:
不能通过连接其他符号来创建新的操作符:比如[email protected]重载操作符必须有一个类类型参数
用于内置类型的运算符,其含义不能改变,例如:内置的整型+,不能改变其含义
作为类成员函数重载时,其形参看起来比操作数数目少1,因为成员函数的第一个参数为隐藏的this
.* :: sizeof ?: .
注意以上5个运算符不能重载。这个经常在笔试选择题中出现。
class Date
{
public:
Date(int year = 1, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
//写一个公有的函数避免在类外不能使用的情况——麻烦
//int GetYear()
//{
// return _year;
//}
//直接写进类里,但是参数过多
bool operator==(const Date& x)
{
return _year == x._year
&& _month == x._month
&& _day == x._day;
}
private:
int _year;
int _month;
int _day;
};
//bool DateEquel(Date x1, Date x2)
//bool func(Date x1, Date x2)
//bool riqixiangdeng(Date x1, Date x2)
//{
// return x1._year == x2._year
// && x1._month == x2._month
// && x1._day == x2._day;
//}
//函数的类型是运算之后的返回值决定的
//bool operator==(Date x1, Date x2)//第一个参数是左操作数,第二个操作数是右操作数
//bool operator==(const Date& x1, const Date& x2)
//{
私有的在类外面不能直接访问
// return x1._year == x2._year
// && x1._month == x2._month
// && x1._day == x2._day;
//}
//int operator-(Date x1, Date x2)
//{}
int main()
{
Date d1(2022, 7, 23);
Date d2(2022, 7, 24);
// 内置类型可以直接使用运算符运算,编译器知道要如何运算
// 自定义类型无法直接使用运算法,编译器也不知道要如何运算。想支持,自己实现运算符重载即可
//cout << operator==(d1,d2) << endl;//可以写自定义函数,可读性差
cout << d1.operator==(d2) << endl; // -> d1.operator==(&d1, d2)
cout << (d1 == d2) << endl;//编译器会自动转换成cout << operator==(d1,d2) << endl;
自定义类型:
//d1 < d2;
//d1++;
//d1 + 100;
//Date d3(2022, 10, 1);
//d3 - d2;
return 0;
}
class Date
{
public:
int GetMonthDay(int year, int month)
{
//静态区——每次访问同一个
static int days[13] = {
0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
//if (month == 2 && IsLeapYear(year))
if (month == 2
&& ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)))
{
return 29;//闰年
}
else
{
return days[month];
}
}
Date(int year = 1, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
bool operator==(const Date& x)
{
return _year == x._year
&& _month == x._month
&& _day == x._day;
}
bool operator<(const Date& x);
bool operator>(const Date& x);
bool operator>=(const Date& x);
bool operator<=(const Date& x);
bool operator!=(const Date& x);
// d1 += 100;
Date& operator+=(int day)
{
_day += day;
while (_day > GetMonthDay(_year, _month))
{
_day -= GetMonthDay(_year, _month);
++_month;
if (_month == 13)
{
_month = 1;
_year++;
}
}
return *this;//this指针就是当前对象
}
// d1 + 100;日期加100天还是日期所以类型是date
Date operator+(int day)
{
Date ret(*this);
ret._day += day;
while (ret._day > GetMonthDay(ret._year, ret._month))
{
ret._day -= GetMonthDay(ret._year, ret._month);
++ret._month;
if (ret._month == 13)
{
ret._month = 1;
ret._year++;
}
}
return ret;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1(2022, 7, 23);
//Date d2(2022, 7, 24);
//d1 == d2;
//d1 < d2;
Date ret = d1 + 50;
//Date ret(d1 + 50);
/*d1 += 50;*/
//d1++;
/*int i = 10; i + 50;//i不变 i += 50;//i才变*/
//Date d3(20202, 10, 1);
//d3 - d2;
return 0;
}
5.2 赋值运算符重载
- 赋值运算符重载格式
参数类型
:const T&,传递引用可以提高传参效率
返回值类型
:T&,返回引用可以提高返回的效率,有返回值目的是为了支持连续赋值,检测是否自己给自己赋值
返回*this
:要复合连续赋值的含义
class Date
{
public :
Date(int year = 1900, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
Date (const Date& d)
{
_year = d._year;
_month = d._month;
_day = d._day;
}
Date& operator=(const Date& d)
{
if(this != &d)
{
_year = d._year;
_month = d._month;
_day = d._day;
}
return *this;
}
private:
int _year ;
int _month ;
int _day ;
};
- 赋值运算符只能重载成类的成员函数,不能重载成全局函数
原因
:
赋值运算符如果不显式实现,编译器会生成一个默认的。此时用户再在类外自己实现一个全局的赋值运算符重载,就和编译器在类中生成的默认赋值运算符重载冲突了,故赋值运算符重载只能是类的成员函数
《C++ prime》中说明我们可以重载赋值运算符。不论形参的类型是什么,赋值运算符都必须定义为成员函数
- 用户没有显式实现时,编译器会生成一个默认赋值运算符重载,以值的方式逐字节拷贝。
注意
:内置类型成员变量是直接赋值的,而自定义类型成员变量需要调用对应类的赋值运算符重载完成赋值
6.日期类的实现和前置++和后置++重载
Date.cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include "Date.h"
void Date::Print()
{
cout << _year << "/" << _month << "/" << _day << endl;
}
// 任何一个类,只需要写一个> == 或者 < ==重载 剩下比较运算符重载复用即可
//类作为一个整体,上下都会搜索,所以谁复用谁的顺序无所谓
bool Date::operator== (const Date& d)
{
return _year == d._year
&& _month == d._month
&& _day == d._day;
}
// d1 != d2 复用就可以
bool Date::operator!=(const Date& d)
{
return !(*this == d);
}
// d1 > d2
bool Date::operator>(const Date& d)
{
if ((_year > d._year)//年大就大
|| (_year == d._year && _month > d._month)//年相等,月大就大
|| (_year == d._year && _month == d._month && _day > d._day))//年月想等,天大就大
{
return true;
}
else
{
return false;
}
}
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 !(*this > d);
}
// d2 += d1 += 100 自己的值也要改变,返回值就是自己
Date& Date::operator+=(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;//this指针就是当前的自己
}
// d1 + 100 自己不改变,返回值是另一个对象
Date Date::operator+(int day)
{
//Date ret(*this);
Date ret = *this;//拷贝构造,不是赋值
ret += day;
return ret;
}
//反过来复用——+=会变低效,拷贝构造会变多
//Date Date::operator+(int day)
//{
// Date ret = *this;
// // ...
// ret._day += day;
// while (ret._day > GetMonthDay(ret._year, ret._month))
// {
// //...
// }
//
// return ret;
//}
//
d1 += 100
//Date& Date::operator+=(int day)
//{
// *this = *this + day;
//
// return *this;
//}
Date& Date::operator++() // 前置,返回++之后的
{
//*this += 1;
//return *this;
return *this += 1;
}
Date Date::operator++(int) // 后置,返回++之前的
{
Date tmp(*this);
*this += 1;
return tmp;
}
// // 后置--
Date Date::operator--(int)
{
Date ret(*this);
*this -= 1;
return ret;
}
// 前置--
Date& Date::operator--()
{
*this -= 1;
return *this;
//return *this -= 1;
}
// d1 - d2
// 日期-日期 返回天数
Date Date::operator-(int day)
{
Date ret = *this;//拷贝构造
ret -= day;
return ret;
}
Date& Date::operator-=(int day)
{
if (day < 0)
{
return *this += -day;
}
_day -= day;
while (_day <= 0)
{
--_month;
if (_month == 0)
{
--_year;
_month = 12;
}
_day += GetMonthDay(_year, _month);
}
return *this;
}
//简单写法——不复用
//深度复用
int Date::operator-(const Date& d)
{
int flag = 1;
Date max = *this;
Date min = d;
if (*this < d)
{
max = d;
min = *this;
flag = -1;
}
int n = 0;
while (min != max)
{
++min;
++n;
}
return n*flag;
}
//void Date::operator<<(ostream& out)//out就是cout的别名
//{
// out << _year << "-" << _month << "-" << _day << endl;
//}
Date.h
#pragma once
#include<iostream>
#include<assert.h>
using namespace std;
// 一个到底可以重载哪些运算符?——> 哪些运算符对这个类型有意义
class Date
{
//友元函数 - -在这个函数内部可以使用Date对象访问私有保护成员
friend ostream& operator<<(ostream& out, const Date& d);
friend istream& operator>>(istream& out, Date& d);
public:
// 获取某年某月的天数
// 会频繁调用,所以直接放在类里面定义作为inline
int GetMonthDay(int year, int month)
{
static int days[13] = {
0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
int day = days[month];
if (month == 2
&& ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)))
{
day += 1;
}
return day;
}
//检查日期,防止使用不合法的日期
bool CheckDate()
{
if (_year >= 1
&& _month > 0 && _month <13
&& _day >0 && _day <= GetMonthDay(_year, _month))
{
return true;
}
else
{
return false;
}
}
// 构造会频繁调用,所以直接放在类里面定义作为inline
Date(int year = 1, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
1.
//if (!this->CheckDate())
//{
// Print();
// cout << "刚构造的日期非法" << endl;
//}
//2.
assert(CheckDate());
}
void Print();
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);
Date operator+(int day);
Date& operator+=(int day);
// ++d1;
// d1++;
// 直接按特性重载,无法区分
// 特殊处理,使用重载区分,后置++重载增加一个int参数跟前置构成函数重载进行区分
Date& operator++(); // 前置
Date operator++(int); // 后置
Date& operator--(); // 前置
Date operator--(int); // 后置
Date operator-(int day);
Date& operator-=(int day);
//日期-日期是天数
int operator-(const Date& d);
/*void operator<<(ostream& out);*/
private:
int _year;
int _month;
int _day;
};
/*ostream& operator<<(ostream& out, const Date& d);*/
//流插入重载
inline ostream& operator<<(ostream& out, const Date& d)
{
out << d._year << "年" << d._month << "月" << d._day << "日" << endl;
return out;
}//写成inline声明和定义不分离
//流提取重载
inline istream& operator>>(istream& in, Date& d)
{
in >> d._year >> d._month >> d._day;
assert(d.CheckDate());
return in;
}
test.cpp
//菜单
void TestDate2()
{
const char* WeeDayToStr[] = {
"周一", "周二", "周三", "周四", "周五", "周六", "周天" };
Date d1, d2;
int day = 0;
int option = 0;
do{
cout << "*****************************" << endl;
cout << " 1.日期加、减天数 2.日期减日期" << endl;
cout << " 3.日期->周几 -1.退出" << endl;
cout << "*****************************" << endl;
cin >> option;
cout << "请选择:";
if (option == 1)
{
cout << "请一次输入日期及天数(减天数需要输入负数):";
cin >> d1 >> day;
cout <<"日期加减天数后的日期:"<< d1 + day << endl;
}
else if (option == 2)
{
cout << "请依次输入两个日期:";
cin >> d1 >> d2;
cout << "相差的天数:" << d1 - d2 << endl;
}
else if (option == 3)
{
cout << "请输入日期:";
cin >> d1;
Date start(1, 1, 1);
int n = d1 - start;
int weekDay = 0; // 周一
weekDay += n;
//weekDay += 9;
//cout << "周" << weekDay % 7 + 1 << endl;
cout << WeeDayToStr[weekDay % 7] << endl;
}
else
{
cout << "无此选项,请重新选择" << endl;
}
} while (option != -1);
}
int main()
{
TestDate2();
return 0;
}
int i = 0;
double d = 1.1;
cout << i;//cout.operator<<(i);
cout << d;//cout.operator<<(d);
- 库里面写好了运算符重载
- 自动识别类型,它们构成函数重载
运算符重载
:让自定义类型对象可以用运算符。转换成调用这个重载函数函数重载
:支持函数名相同的函数同时存在
两者虽然都用了重载这个词,但是它们之间没有必然联系。
7.const成员
将const修饰的“成员函数”称之为const成员函数,const修饰类成员函数,实际修饰该成员函数隐含的this指针,表明在该成员函数中不能对类的任何成员进行修改。
void TestDate6()
{
Date d1(2022, 7, 25);
const Date d2(2022, 7, 25);
d1.Print();//&d1 ——> Date*
d2.Print();//&d2 ——> const Date*
d1 < d2;
d2 < d1;
}
int main()
{
TestDate6();
return 0;
}
const本身不能被修改但是有一次初始化的机会
Date*传Date*可以
const Date*传Date*属于权限的放大,不可行
void Date::Print()//Date* const this
{
cout << _year << "/" << _month << "/" << _day << endl;
}
bool Date::operator<(const Date& d)///Date* const this
{
return !(*this >= d);
}
修改:
void Date::Print() const //const修饰的是this指针指向的内容
{
this ->_year = 1;//报错,不能被修改
cout << _year << "/" << _month << "/" << _day << endl;
}
bool Date::operator<(const Date& d) const
{
return !(*this >= d);
}
第一个也没有问题,因为Date* 传const Date*属于权限的缩小
const修饰的是this指针指向的内容,也就是保证了成员函数内部不会修改成员变量
const对象和非const对象都可以调用这个成员函数
8.取地址及const取地址操作符重载
这两个默认成员函数一般不用重新定义 ,编译器默认会生成。
这两个运算符一般不需要重载,使用编译器生成的默认取地址的重载即可,只有特殊情况,才需要重载,比
如想让别人获取到指定的内容!
class A
{
public:
// 他们是默认成员函数,我们不写编译器会自动生成,自动生成就够用了,所以一般是不需要我们自己写的
// 特殊场景:不想让别人取到这个类型对象的地址
A* operator&()
{
return nullptr;//返回空指针或者设为私有
}
const A* operator&()const
{
return nullptr;
}
void Print() const
{
//_year = 1;
cout << _year << "/" << _month << "/" << _day << endl;
}
/*void Print()//构成函数重载 { _year = 1; cout << _year << "/" << _month << "/" << _day << endl; }*/
private:
int _year; // 年
int _month; // 月
int _day; // 日
};
int main()
{
A d1;
const A d2;
d1.Print();//权限的缩小
d2.Print();//权限的平移
cout << &d1 << endl;
cout << &d2 << endl;
return 0;
}
边栏推荐
- How to build an overseas purchasing system/purchasing website - source code analysis
- 技术分享 | 接口自动化测试如何搞定 json 响应断言?
- Station B responded that "HR said that core users are all Loser": the interviewer was persuaded to quit at the end of last year and will learn lessons to strengthen management
- 基于php校园医院门诊管理系统获取(php毕业设计)
- 博客记录生活
- How can I get a city's year-round weather data for free?Precipitation, temperature, humidity, solar radiation, etc.
- R语言绘制时间序列的自相关函数图:使用acf函数可视化时间序列数据的自相关系数图
- 4500 words sum up, a software test engineer need to master the skill books
- Database basics one (MySQL) [easy to understand]
- net start mysql 启动报错:发生系统错误5。拒绝访问。
猜你喜欢
随机推荐
The new interface, jingdong comment interface
Apache APISIX 2.15 版本发布,为插件增加更多灵活性
Redis连接池工具类
项目概述、推送和存储平台准备
【Verilog】HDLBits题解——验证:阅读模拟
五、函数的调用过程
Unsupervised learning KMeans notes and examples
ROS中编译通过但是遇到可执行文件找不到的问题
【Verilog】HDLBits题解——Circuits/Sequential Logic/Latches and Flip-Flops
bash while loop and until loop
解决oracle安装在linux中jdk的冲突
基于php网上零食商店管理系统获取(php毕业设计)
特征降维学习笔记(pca和lda)(1)
What knowledge points do you need to master to learn software testing?
php microtime encapsulates the tool class, calculates the running time of the interface (breakpoint)
无监督学习KMeans学习笔记和实例
秋招招工作
特征工程学习笔记
Oracle is installed (system disk) and transferred from the system disk to the data disk
R语言拟合ARIMA模型并使用拟合模型进行预测推理、使用autoplot函数可视化ARIMA模型预测结果、可视化包含置信区间的预测结果