运算符重载(下)
目录
- 前置++和后置++重载
- 前置++的实现
- Date& Date::operator++()代码
- 后置++的实现
- Date Date::operator++(int )代码
- 前置--和后置--重载
- 前置--的实现
- Date& Date::operator--( )代码
- 后置--的实现
- Date Date::operator--(int )代码
- 流插入运算符重载
- 流插入运算符重载的实现
- 流提取运算符重载的实现
- 日期类的检查函数
- const成员函数
- const对象不可以调用非const成员函数
- 非const对象可以调用const成员函数
- const成员函数内不可以调用其它的非const成员函数
- 非const成员函数内可以调用其它的const成员函
- 取地址及const取地址操作符重载
- const补充
- 场景1
- 场景2
- 场景3
- 场景4
感谢各位大佬对我的支持,如果我的文章对你有用,欢迎点击以下链接
🐒🐒🐒 个人主页
🥸🥸🥸 C语言
🐿️🐿️🐿️ C语言例题
🐣🐣🐣 python
🐓🐓🐓 数据结构C语言
🐔🐔🐔 C++
🐿️🐿️🐿️ 文章链接目录
前置++和后置++重载
前置++是先++再使用
后置++是先使用再++
用operator实现前置和后置++感觉非常难
因为operator++只能实现这两个的其中一个功能,为了解决这个问题就需要让operator可以特殊处理
为了让operator++可以进行区分,可以让其中的一个operator++强行增加一个int参数构成重载来区分
注意这里的int是被规定的
所以Date& Date::operator++()表示前置++,Date Date::operator++(int )表示后置++,编译器会自动识别
前置++的实现
因为前置++要求的是先++再使用,所以返回的结果应该是修改完后的对象,返回方式是引用返回,因为可能要支持连续赋值
Date& Date::operator++()代码
//++d
Date& Date::operator++()
{*this += 1;return *this;
}
后置++的实现
后置++是先用后++,所以返回的方式不可以是引用返回,因为引用返回是返回的修改后的对象,而我们需要的是返回修改前的对象
所以需要将修改前的对象先拷贝构造出一个局部对象tmp,然后修改再修改this指针,最后再将tmp返回(注意这里tmp是局部对象,出了作用域就会销毁,但是由于我们没有用引用,所以返回的tmp是被拷贝了的,tmp被销毁并不影响)
Date Date::operator++(int )代码
//d++
Date Date::operator++(int )
{Date tmp = *this;*this += 1;return tmp;
}
后置++要想打印返回的结果可以将d1++用括号括起来,因为返回的是一个对象,所以(d1++).Print也是可以打印出结果的
如果不括起来就只能打印修改后的对象
前置++和后置++也可以显示写的
前置要写成d1. operator()
后置要写成d1. operator(0),注意这里的0可以是任意整形
前置++和后置++相比,前置++的使用效率会略高一些,因为前置++是通过引用返回,而后置++是传引用返回,传值和传引用的返回效率会有所不同,所以在能使用前置++的情况下我们通常都会使用前置++
前置–和后置–重载
前置–的实现
Date& Date::operator–( )代码
后置–的实现
Date Date::operator–(int )代码
流插入运算符重载
C++中我们并不能通过cout<<d1<<endl去打印对象
而是通过调用Print()函数去打印,但是有了operator后我们就可以实现流插入运算符重载
流插入运算符重载的实现
void operator <<(ostream& out){cout << _year << "年" << _month << "月" << _day << "日" << endl;}
这里的ostream&表示这个函数接收的是一个输出流对象
这个代码运行后却报错了
那我们这样写呢?
在(运算符重载(上))中有提到过
像运算符重载(上)中实现的比较函数如operator<( const Date& y)
d1<d2其实是d1.operator<(d2)
那这样说cout<<d1就应该是cout.operator<<(d1),这显然是不对的,当我们d1.operator<<(cout)时是可以正常运行的,所以最后的结果是我们写反了😂😂😂
应该把cout<<d1写成d1<<cout
作为成员函数重载,this指针占据第一个参数,所以Date必须是左操作数,而Date必须是左操作数就说明我们不可以让ostream的对象占据左操作数
但是我们就想写成cout<<d1应该怎么改办呢?
对于上面的话只是针对成员函数重载,要想写成cout<<d1,我们只需要不写成成员函数而是写成全局函数就可以了
然而写成全局函数就出现了一个问题,就是访问的权限,因为之前的函数是成员函数,可以访问私有的成员变量
而现在写成了全局函数之后,就会因为private限制访问,当我们删除了private后再运行依然报错
这里的找到一个或多个重定义的符号报错的原因是因为void operator <<(ostream& out, const Date& d)函数在头文件中定义,而其他文件包含了Date.h这个头文件,在程序预处理阶段会将Date.h展开,所以需要声明和定义分离
C++中的流插入是可以支持连续输出的,所以我们还需要再对函数改改,让他的返回值变成一个输出流对象的别名
ostream& operator <<(ostream& out, const Date& d)
{cout << d._year << "年" << d._month << "月" << d._day << "日" << endl;return out;
}
虽然代码可以正常运行了,但是我们是通过将私有删除才成功的,而私有删除会导致可以随便修改对象里的成员变量
解决这个问题的方法是我们不删除私有,而是提供一个Getyear Getmonth Getday函数,这样全局函数就可以这些函数去访问了
还有一种方法就是友元声明
友元函数用一个例子解释的话就是:同学A的允许不认识的人拿他的东西,而同学B一开始是不认识同学A的,在通过友元函数后和同学A相互认识了,所以现在同学B可以拿同学A的东西
流提取运算符重载的实现
istream& operator >>(istream& in, Date& d)
{cout << "请依次输入年月日>";in >> d._year >> d._month >> d._day;return in;
}
istream&是输入流对象
从流提取中我们也可以理解C语言的scanf为什么需要传地址了,因为我们输入的值需要对变量进行修改,只有找到变量的地址,通过解引用才能够修改变量
日期类的检查函数
对于之前写的日期类函数有一个小问题,就是有的人写的日期会不符合常理
我们需要有一个检查的函数去告诉我们这个日期是错误的
bool Date::CheckInvalid()
{if (_year <= 0||_month<1||_month>12||_day<1||_day>GetMonthDay(_year,_month)){return false;}return true;
}
Date::Date(int year,int month,int day)
{_year = year;_month = month;_day = day;if (!CheckInvalid()){cout << "构造日期非法" << endl;}
}
然后将这个函数加入构造函数中,因为所有的对象都是通过构造函数构造出来的,需要保证构造函数不会出错,其次还有流提取函数
istream& operator >>(istream& in, Date& d)
{while (1){cout << "请依次输入年月日>";in >> d._year >> d._month >> d._day;if (!d.CheckInvalid()){cout << "输入无效日期,请重新输入" << endl;}elsebreak;}return in;
}
const成员函数
将const修饰的“成员函数”称之为const成员函数,const修饰类成员函数,实际修饰该成员函数
隐含的this指针,表明在该成员函数中不能对类的任何成员进行修改。
const对象不可以调用非const成员函数
这是Print函数,当我们用const修饰的对象去调用他时
void Print(){cout << _year << "/" << _month << "/" << _day << endl;}
const修饰对象报错常见的就是权限的放大问题
d1被const修饰后是不可以修改,而Print函数传参时是隐藏了this指针的,也就是说print函数传的参数是d1的地址,将d1的地址穿进去后就有可能会修改d1,所以这是权限放大的原因
要解决问题就需要用const去修饰函数
void Print()const
{cout << _year << "/" << _month << "/" << _day << endl;
}
这里的const是修饰this指针指向的内容,注意const修饰的方式是void Print()const,而不是const void Print()或void const Print()
如果对于全局函数就不能像上面修饰的一样了
void operator <<(ostream& out) 不能修饰成 operator <<(ostream& out)const
void operator >>(ostream& in,Date &d) 不能修饰成 void operator >>(ostream& in,Date &d)const
要搞清楚const是想要修饰什么,void Print()const修饰的是隐藏的this指针
operator <<(ostream& out)和 void operator >>(ostream& in,Date &d)根本就没有隐藏的this指针,所以不需要在后面加const
即使想要加const也要这样加 void operator >>(ostream& in,const Date &d)(但是这样是错误的,因为流提前要改变对象,所以不应该加const,这里只是演示该加在哪)
非const对象可以调用const成员函数
非const对象可以调用const成员函数是因为d1没有被const修饰,所以他是可读可写的,而Print函数被const修饰后只要求可以读取数据内容,并不要求修改数据,所以当然可以,可以把这里理解成权限的缩小
要注意对于只要求读取数据的函数可以加上const修饰,但不用让所以函数都被const修饰,因为如果有的函数要求修改数据,加上const后就会出现权限放大问题
总结
成员函数中如果是一个对成员变量只进行读访问的函数建议加上const修饰,这样被const修饰的对象和没变const修饰的对象都可以使用
如果是对成员变量进行读写访问的函数,不能加上const修饰,否则会出现权限放大问题
const成员函数内不可以调用其它的非const成员函数
这里还是权限放大问题,const修饰的成员函数表示这个函数内部都是不可以修改Date的成员变量的,而如果里面出现了非const的成员函数,就表示里面可以修改成员变量,这显然不行
非const成员函数内可以调用其它的const成员函
这是权限缩小,所以可以
总之const修饰后的对象注意一下权限是否变大就行了
取地址及const取地址操作符重载
这两个默认成员函数一般不用重新定义 ,编译器默认会生成。
这两个运算符一般不需要重载,使用编译器生成的默认取地址的重载即可,只有特殊情况,才需要重载,比如想让别人获取到指定的内容
class Date
{
private:int _year;
};
class A
{
public:A* operator&(){return this;}const A* operator&()const{return this;}
};
int main()
{A aa1;const A aa2;cout << &aa1 << endl;cout << &aa2 << endl;return 0;
}
A* operator&()和const A* operator&()const是想返回this指针,而返回的this指针有差别
A* operator&()对传入的this指针没有进行const修饰,并且返回的this指针也没有进行const修饰
而const A* operator&()const对传入的this指针进行了修饰,并且返回的this指针也进行了const修饰
通过调用这两个函数得到的this指针可以直接打印出this指针的值
当我们屏蔽掉上面的代码后,也可以正常运行,因为这是默认成员函数,我们不写编译器会生成,而这两个默认成员函数并不像我们之前写的拷贝函数和析构函数等等默认成员函数那样复杂,这两个默认成员函数就是返回一个this指针,所以日常都不需要我们写,编译器默认生成的函数就够用了
那什么时候是需要我们写的呢?
比如我们只想让被const修饰后的成员函数拿到地址,这样做的目的就是不想有人拿到地址后乱搞
class Date
{
private:int _year;
};
class A
{
public:A* operator&(){return nullptr;}const A* operator&()const{return this;}
};
int main()
{A aa1;const A aa2;cout << &aa1 << endl;cout << &aa2 << endl;return 0;
}
甚至我们还可以返回一个假地址
const补充
场景1
int main()
{const int i = 0;int j = i; cout << j << endl;return 0;
}
这里j=i没有报错是因为j是i的拷贝,将i的值拷贝给了j
场景2
int main()
{const int i = 0;int& r = i; cout << r << endl;return 0;
}
这里的r是i的别名,r被修改会导致i也会被修改,所以报错
场景3
int main()
{int i = 0;const int* p1 = &i;int* p2 = p1;return 0;
}
const修饰p1表示不可以通过p1去修改p1指向的值i,换句话来说就是不可以修改p1
但是可以修改p1指向的地址,也就是p1可以被修改
上面的代码中 int p2 = p1是想将p1指向的地址传给p2,而p1指向的地址是&i
根据前面的结论,const修饰p1表示p1不可以被修改,而p1将i的地址给了p2,p2就可以通过p1给的地址去修改i,也就间接的使*p1修改了,所以才会报错
场景4
int main()
{int i = 0;int* const p1 = &i;int* p2 = p1;return 0;
}
const修饰p1表示p1不可以被修改,因为p1是一个指针,而p1保存的是i的地址,p1不能被修改意思就是i的地址不可以修改
将p1的值给p2,这里并不会报错,我猜测可能p2也是拷贝了p1的地址,所以p2的改变不会影响p1
如果想让上面的代码报错,我们可以修改p1,让p1保存另一个变量j的地址,因为const修饰的是p1,p1是不能变的,所以就会报错
相关文章:

运算符重载(下)
目录 前置和后置重载前置的实现Date& Date::operator()代码 后置的实现Date Date::operator(int )代码 前置--和后置--重载前置--的实现Date& Date::operator--( )代码 后置--的实现Date Date::operator--(int )代码 流插入运算符重载流插入运算符重载的实现流提取运算…...

杭州服务器的性能如何?
挥洒激情,开启杭州服务器的无限可能! 互联网时代,服务器的性能就如同一艘航空母舰,承载着企业的发展梦想,指引着行业的发展方向。而对于杭州服务器,其性能究竟如何?让我来告诉您。 杭州服务器…...

linux centos nfs挂载两台服务器挂载统一磁盘目录权限问题
查看用户id id 用户名另一台为 修改uid和gid为相同id,添加附加组 usermod -u500 -Gwheel epms groupmod -g500 epms...

STL:string
文章目录 标准库中的string类string的构造string的赋值重载string的容量size(length)max_sizeresizereservecapacityclearemptyshink_to_fit string的元素访问operator[] 和 atfront 和 back string的迭代器 和 范围forstring的修改operatorappendpush_backassigninserterasere…...

贷款借钱平台 小额贷款系统开发小额贷款源码 贷款平台开发搭建
这款是贷款平台源码/卡卡贷源码/小贷源码/完美版 后台51800 密码51800 数据库替换application/database.php程序采用PHPMySQL,thinkphp框架代码开源,不加密后台效果:手机版效果 这款是贷款平台源码/卡卡贷源码/小贷源码/完美版 后台51800 密码…...

软设之算法的效率
算法的效率分为时间复杂度和空间复杂度。 空间复杂度是指对一个算法在运行过程中临时占用存储空间大小的度量。一个算法的空间复杂度只考虑在运行过程中为局部变量分配的存储空间的大小。说白了,就是空间换时间。 比如说计算从123……100的和。一个算法是i(1100)*…...

前端开发(2)--HTML常用的标签
100编程书屋_孔夫子旧书网 HTMl 的标签可以分为单个标签和成对标签。 单个标签:html4 规定单个标签要有一个 / 表示结尾, html5 则不用 <!--单个标签--> <meta> <!--成对标签 --> <div></div>以下是HTMl中常用的一些标签…...

任何图≌自己这一几何最起码常识推翻直线公理让R外标准实数一下子浮出水面
黄小宁 h定理:点集AB≌B的必要条件是A≌B。 证:若AB则A必可恒等变换地变为BA≌A,而恒等变换是保距变换。证毕。 如图所示R轴即x轴各元点x沿x轴正向不保距平移变为点y2x就使x轴沿本身拉伸(放大)变换为y2x轴不≌x轴&…...

js 纯前端实现数组分页、列表模糊查询、将数组转成formdata格式传给接口
后端返回所有的数据,由前端来实现分页展示、模糊查询,并将数组格式转成formdata格式给后端 1、数组转formdata let formData new FormData()for (let i 0; i < list.length; i) {let item list[i];for (let property in item) {formData.append(…...

elasticsearch有什么用
Elasticsearch是一个开源的分布式搜索和分析引擎,它被广泛用于构建实时的、可扩展的搜索和分析应用程序。以下是Elasticsearch的主要用途和功能:12 全文搜索:Elasticsearch提供强大的全文搜索功能,可以处理大量的文本数据&…...

iOS自动连接已知Wi-Fi功能的实现
首先需要在配置文件申请的时候将hotspot勾选上,之后还要在x-code里添加对应的配置,由于我们并没有用到获取设备周边Wi-Fi的功能,所以就没申请相关权限 相关连接Wi-Fi代码如下: #import <NetworkExtension/NetworkExtension.h&…...

编辑任何场景! 3DitScene:通过语言引导的解耦 Gaussian Splatting开源来袭!
文章:https://arxiv.org/pdf/2405.18424 项目:https://zqh0253.github.io/3DitScene/ huggingface:https://huggingface.co/spaces/qihang/3Dit-Scene 场景图像编辑在娱乐、摄影和广告设计中至关重要。现有方法仅专注于2D个体对象或3D全局场景编辑&…...

CCIG 2024:合合信息文档解析技术突破与应用前景
目录 背景当前大模型训练和应用面临的问题训练Token耗尽训练语料质量要求高LLM文档问答应用中文档解析不精准 合合信息的文档解析技术1. 具备多文档元素识别能力2. 具备版面分析能力3. 高性能的文档解析4. 高精准、高效率的文档解析文档多板式部分示例 文档解析典型技术难点元素…...

关于TeamSpeak3-网易音乐机器人的基础使用方法(胎教级教程)
本文转自博主的个人博客:https://blog.zhumengmeng.work,欢迎大家前往查看。 原文链接:点我访问 序言:在自己的ts服务器上安装了网易音乐机器人,写这篇文章旨在教群友/网友如何使用机器人!😋👍 一、TS3Audi…...

看广告赚金币提现小游戏app开发源码
开发一个看广告赚金币并可以提现的小游戏APP,源码的搭建涉及到多个方面,包括前端界面设计、后端逻辑处理、数据库管理以及广告平台的对接等。以下是一些建议的步骤和考虑因素: 前端界面设计: 使用HTML5、CSS3和JavaScript等技术…...

【vue】@、@/、../和./的区别
:表示vue语法中v-on的简写;绑定事件的专用格式。当事件触发的时候,函数才会来调用; /:在build文件夹下webpack.base.conf.js找到,便能知道代表什么了; 这里指向src文件夹 . /:表示当前目录下&…...

imx93 uboot 构建
1. 信息来源 从 nxp 的英文网站中可以找到 imx93 的构建信息,当前的最新版本为:Linux 6.6.3_1.0.0 # 网址如下: https://www.nxp.com/design/design-center/software/embedded-software/i-mx-software/embedded-linux-for-i-mx-application…...

视觉SLAM十四讲:从理论到实践(Chapter7:视觉里程计1)
前言 学习笔记,仅供学习,不做商用,如有侵权,联系我删除即可 一、目标 1.理解图像特征点的意义,并掌握在单幅图像中提取特征点及多幅图像中匹配特征点的方法。 2.理解对极几何的原理,利用对极几何的约束&…...

c++指针的*
1.*运算符 *运算符被称为间接值(indirect value)或者解除引用(dereferencing)运算符 将其应用于指针可以得到该地址处存储的值 由于 * 也有乘法的意思,c通过上下文来确定是乘法还是解除引用 2.如何声明和初始化指针 …...

快团团大团长帮卖团长团长如何获得物流查询码?
一、功能说明 团长可自行生成物流查询码,直接将码发给顾客,顾客扫码可查询自己订单的物流状态! 用户扫码后,会出现用户在该团长处下单的所有快递订单。团员可查看该订单物流信息、进行退款申请,或直接联系团长。 二…...

MySQL(二)基本SQL语句以及基本函数应用
1、基本SQL语句 MySQL中定义数据字段的类型对你数据库的优化是非常重要的。 MySQL支持多种类型,大致可以分为三类:数值、日期/时间和字符串(字符)类型。 - 函数应用在sql语句中 -- 临时表 select now() from dual;-- 数学函数 二进制 -- 返回x的绝对值 select a…...

fyne apptab布局
fyne apptab布局 AppTabs 容器允许用户在不同的内容面板之间切换。标签要么只是文本,要么是文本和一个图标。建议不要混合一些有图标的标签和一些没有图标的标签。 package mainimport ("fyne.io/fyne/v2/app""fyne.io/fyne/v2/container"//&…...

Python实现定时任务的方式
大家好,在当今数字化的时代,定时任务的需求在各种应用场景中频繁出现。无论是数据的定时更新、周期性的任务执行,还是特定时间点的操作触发,Python 都为我们提供了强大而灵活的手段来实现这些定时任务。当我们深入探索 Python 的世…...

微信小程序-网络数据请求(配置request合法域名)
1.小程序中网络数据请求的限制 出于安全方面的考虑,小程序官方对数据接口的请求做出了如下两个限制: (1)只能请求HTTPS类型的接口 (2)必须将接口的域名添加到信任列表中 如果要请求某个域名下的接口&am…...

栈和队列题目练习
本节小编选了两道题来加深对栈和队列的认识理解! 有效的括号 方法1:直接用栈的结构(动态数组) 本题可以用栈这个结构来解答,将(,{,[ 左括号压入栈中,然后取出栈顶元素与右括号),},]匹配。不匹配的话&…...

【排列问题】
问题: 已知某序列有n个元素,请编写程序打印出包含该序列所有元素的所有排列。 输入要求: 输入第1行为整数n,表示该序列元素的个数;第2行为n个整数,表示需要排列的序列元素。 输出要求:输出若…...

token 无感刷新
什么是 token 无感刷新?为什么需要 token 无感刷新?让我们想象一下有这么个场景:你登录一个系统成功后,玩了 10 分钟,发现登录失效了,又要你重新登录,然后又过 10 分钟,又失效了&…...

Netty SSL双向验证
Netty SSL双向验证 1. 环境说明2. 生成证书2.1. 创建根证书 密钥证书2.2. 生成请求证书密钥2.3. 生成csr请求证书2.4. ca证书对server.csr、client.csr签发生成x509证书2.5. 请求证书PKCS#8编码2.6. 输出文件 3. Java代码3.1. Server端3.2. Client端3.3. 证书存放 4. 运行效果4…...

4.nginx反向代理、负载均衡
nginx反向代理、负载均衡 一、反向代理1、语法2、注意事项3、后端服务器记录客户端真实IP3.1 在nginx反向代理时添加x-real-ip字段3.2 后端httpd修改combined日志格式3.3 后端是nginx的情况 二、负载均衡 upstream模块1、负载均衡作用2、调度算法3、配置应用 一、反向代理 隐藏…...

浅谈申请小程序地理位置权限的正确打开方式
小程序地理位置接口有什么功能? 这篇内容会教大家如何快速申请“获取当前的地理位置(onLocationChange)”接口,以便帮助大家顺利开通接口。以下内容是本人经历了多次的申请经历得出来的经验,来之不易,望大家…...