当前位置: 首页 > news >正文

类和对象(4)--《Hello C++ Wrold!》(6)--(C/C++)--赋值运算符重载,取地址和const取地址操作符重载

文章目录

  • 前言
  • 类的剩下三个默认成员函数
    • 赋值运算符重载
      • 运算符重载
      • 赋值运算符重载
      • 基本流运算符重载
    • 取地址及const取地址操作符重载
      • 关于const的引申
  • 作业部分

前言

这期的话会讲解剩余的三个默认成员函数–赋值运算符重载,取地址和const取地址操作符重载

类的剩下三个默认成员函数

赋值运算符重载

运算符重载

作用:让eg:+在自定义类型中也能使用

函数名字为:关键字operator后面接需要重载的运算符符号。

函数原型:返回值类型 operator操作符(参数列表)

eg: bool operator +(const Data& a)
延申: bool ret = 1<2;这样也是可以的:ret会 = true;operator左右操作数的取哪个跟左右结合性无关哈

1.不能通过连接其他符号来创建新的操作符:比如operator@

2.重载操作符必须有一个类类型参数或者枚举类型(成员函数的话,this也算类类型参数)

3.用于内置类型的运算符,其含义不能改变,例如:内置的整型+,不 能改变其含义

作为类成员函数重载时,其形参看起来比操作数数目少1,因为成员函数的第一个参数为隐藏的this

.*          ::        sizeof       ?:          .
(这个易忘)

注意以上5个运算符不能重载。这个经常在笔试选择题中出现。

运算符重载是可以显示调用的

Date& operator=(const Date& d)//d1传给的是this指针,this == &d1
{
_year = d._year;
_month = d._month;
_day = d._day;
}
main函数里面 d1 = d2
//等效为d1.operator=(d2),像这种两个操作数的都是这样看的,前面那个在operator前面……
//operator=(&d1, d2)

要注意的是运算符重载和拷贝构造函数区分

d2 = d1;//属于已经存在的两个对象之间的复制拷贝的话--运算符重载函数
//不是d1(d2)
Date d2(d1)//用一个已经存在的对象初始化另一个对象--拷贝构造函数
//等价于 Date d2 = d1;

赋值运算符重载

重载时一般要做到这几点才不会错:

参数类型:const 类型&

返回值类型:类型&–不能void,不然连续赋值就遭了

返回*this

注意把自己给自己赋值那个判断一下,提高效率

注意:赋值运算符一定要重载成成员函数,不然系统还会自己再生成一个

Date& operator=(const Date& d){if(this != &d)//这个操作还行{_year = d._year;_month = d._month;_day = d._day;}return *this;}

系统自动生成的赋值重载函数:(跟拷贝构造的这个规则差不多)

1.内置类型成员进行浅拷贝

2.自定义类型成员会去调用他的赋值重载

基本流运算符重载

printf处理不了自定义类型的东西,但是基本流运算符的使用者cin,cout可以

cin(类型是:istream)和cout(类型是:ostream)支持自动识别类型的原因:

1.内置类型是因为库里面实现了

2.支持自定义类型是因为自己写的函数重载

(这个的函数重载的例子也在下面的日期类实现那里)

注意:基本运算符不能写成成员函数

可以显示调用:

cout<<d1;--operator<<(cout,d1);

基本流运算符不能写成成员函数的原因:

要写成成员函数的话,对象要占用operator的左操作数才行(因为this指针会去悄咪咪的占了),写出来就会是下面这个样子,不符合使用习惯

void operator<<(ostream& out);

取地址及const取地址操作符重载

这两个运算符一般不需要重载,使用编译器生成的默认取地址的重载即可,只有特殊情况,才需要重载,比如想让别人获取到指定的内容!

关于const的引申

1.也是有权限缩小,平移,扩大的那个问题

const int a = 10;
int*pb = &a;//这个就算权限扩大了,是不行的

2.成员函数后面加const之后,普通的对象和const过了的对象都可以调用

成员函数加const:
void Print()const这样加const才表示让this指针指向的对象不能被修改

总结对第二点:

只要成员函数内部不修改成员变量,都应该加const,这样const对象和普通对象都可以调用

const对象:比如:const d1(2025,5,7);
在调用时:d2.Print();相当于d2.Print(&d2);this指向d2,所以有了上面那个说法

作业部分

设已经有A,B,C,D4个类的定义,程序中A,B,C,D析构函数调用顺序为?(B)
C c;
int main()
{A a;B b;static D d;return 0;
}
A.D B A C
B.B A D C
C.C D B A
D.A B D C
构造顺序是按照语句的顺序进行构造,析构是按照构造的相反顺序进行析构
然后因为有static,所以d的生存周期变了,但是没C长

在这里插入图片描述

下列关于赋值运算符“=”重载的叙述中,正确的是(A)
A.赋值运算符只能作为类的成员函数重载//理解
B.默认的赋值运算符实现了“深层复制”功能
C.重载的赋值运算符函数有两个本类对象作为形参//这里的形参指的是()里面的
D.如果己经定义了复制拷贝构造函数,就不能重载赋值运算符

在这里插入图片描述

&作取地址和引用的区分:
在描述类型时的&才是引用
日期类的部分实现
class Date
{
friend ostream& operator<<(ostream& out, const Date& d);
public:
// 获取某年某月的天数
int GetMonthDay(int year, int month)
{static int daysArr[13] = { 0, 31, 28, 31, 30, 31, 30,31, 31, 30, 31, 30, 31 };//避免了每次都需要创建//if (((year % 4 == 0 && year % 100 != 0) ||//       (year % 400 == 0)) && month == 2)if (month == 2 && ((year % 4 == 0 && year % 100 != 0) ||(year % 400 == 0)))//这样更好{return 29;}else{return daysArr[month];}
}// 全缺省的构造函数
Date(int year = 1900, int month = 1, int day = 1);// 拷贝构造函数
// d2(d1)
Date(const Date& d);// 赋值运算符重载
Date& operator=(const Date& d);// 析构函数
~Date();Date& Date::operator+=(int day)
{if(day<0)   return *this-=-day;//防止day是负数;这个-=要自己实现!_day += day;while (_day > GetMonthDay(_year, _month)){_day -= GetMonthDay(_year, _month);++_month;if (_month == 13)//这里不是用的while{++_year;_month = 1;}}return *this;
}Date Date::operator+(int day)
{Date tmp(*this);tmp += day;//就像这样,用到之前已经实现了的部分来简化return tmp;// 前置++
Date& operator++()
{*this += 1;return *this;
}// 后置++
Date Date::operator++(int)
{Date tmp = *this;*this += 1;return tmp;
}// 日期-日期 返回天数
int operator-(const Date& d) const
{Date max = *this;Date min = d;int flag = 1;if (*this < d){max = d;min = *this;flag = -1;//表明那个d才是大的}int n = 0;while (min != max){++min;++n;}return n * flag;//flag的巧用,比if来搞好
}int GetYear()
{return _year;//这种方法能让私有的能拿出去
}private:
int _year;
int _month;
int _day;
};ostream& operator<<(ostream& out, const Date& d)
//不能改成 const ostream& out
{out << d._year << "年" << d._month << "月" << d._day << "日" << endl;
//这里不能这样搞,除非设置成友元(像上面写的那样)
//对象的成员函数不是只能用成员变量用return out;
}istream& operator>>(istream& in, Date& d)//注意这两个的类型!
{int year, month, day;in >> year >> month >> day;//感觉还是上面那种读法好些if (month > 0 && month < 13&& day > 0 && day <= d.GetMonthDay(year, month)){d._year = year;d._month = month;d._day = day;}else{cout << "非法日期" << endl;assert(false);//这后面的操作是防止用户输入错误日期}

注意:前置不用加int,后置要加int这个是规定,不能颠倒,参数也不能换成其他类型,让这两个构成重载

在上面的基础上,用eg:d1++;那么编译器就会调用d1.operator(0)//调用时这的int是0

注意:前置返回++之前的对象,后置返回++之后的对象(用来实现前后置效果)

注意:对于内置类型来说,前置和后置的代价差不多,可以忽略不计;但是对自定义类型来说,前置比后置代价小不少(后置需要多构造一个临时对象),平时应该多用前置的

http://www.xdnf.cn/news/585271.html

相关文章:

  • 嵌入式STM32学习——串口USART 2.2(串口中断接收)
  • Python字符串格式化(二): f-string的进化
  • 企业级爬虫进阶开发指南
  • 【linux知识】sftp配置免密文件推送
  • 开搞:第四个微信小程序:图上县志
  • 获取印度股票市场API
  • 关于XILINX的XDC约束文件编写
  • HarmonyOS 鸿蒙应用开发基础:EventHub,优雅解决跨组件通信难题
  • 10.IIC和BH1750
  • 基于单片机的室内采光及可燃气体泄漏报警装置设计
  • SCons构建工具使用指南及示例
  • JAVA SE — 循环与分支和输入输出
  • 有没有开源的企业网盘,是否适合企业使用?
  • 记录:express router,可以让node.js后端文件里的路由分布的更清晰
  • vim以及vi编辑器常用快捷键指令
  • 服务器操作系统调优内核参数(方便查询)
  • 复杂项目中通过使用全局变量解决问题的思维方式
  • 2025中青杯数学建模B题思路+模型+代码
  • 【TTS回顾】CosyVoice 深度解析:基于LLM的TTS模型
  • iOS 直播弹幕功能的实现
  • 前端三件套之html详解
  • DevOps体系之Jmeter
  • java面试每日一背 day2
  • MySQL错误1419(HY000)解决方案:SUPER权限缺失与二进制日志启用冲突的3种处理方式
  • 内存管理子系统学习记录
  • uniapp实现H5、APP、微信小程序播放.m3u8监控视频
  • AVL树的实现
  • 【线段树】P2846 [USACO08NOV] Light Switching G|LG4|普及+
  • 无人机集装箱箱号识别系统准确率如何?能达到多少?
  • 微服务架构中的 RabbitMQ:异步通信与服务解耦(一)