C++类与对象基础(6)

       (注:本篇文章介绍部分内容时,需要用到上盘文章中日期类的代码,文章链接如下:C++类与对象基础(5)——日期类的实现-CSDN博客​​​​​​

目录

1. 运算符重载的相关补充:

1.1流运算符重载出现的问题:

1.2 针对上述问题的解决方法:

1.2.1 通过创建友元函数来实现对私有变量的访问:

2. const成员函数:

2.1 const成员函数基本介绍:

2.2 什么类型的函数需要加:

3.取地址及const取地址操作符重载:


4

1. 运算符重载的相关补充:

1.1流运算符重载出现的问题:

       在对对象进行打印时,一般会在类中编写一个用于打印的成员函数用于打印,即:

void Date::Print()
{cout << _year << " " << _month << " " << _day << endl;
}
int main()
{Date d(2024, 1, 8);d.Print();return 0;
}

运行结果如下:

在针对C++系列的第一篇文章中,就提到了在C++中,输出变量的方法不光只有printf函数,也可以使用流插入cout。上面所展示的代码虽然用到了cout,但是并不是直接调用,而是将cout封装在一个类的成员函数中,进行调用的。如果针对上面的对象d,直接利用cout进行打印,即:

int main()
{cout << d;return 0;
}

 运行代码,此时编译器会显示错误,即:

错误的原因在之前介绍运算符重载的时候提到过:对于自定义类型不能直接调用操作符,而是需要利用运算符重载。因此,为了实现自定义类型变量,即:d,在类中加入一个运算符重载,即:

(注:本篇文章所有的运算符重载都采用声明和定义分离的方式)

void Date::operator<<(ostream& out)
{out << _year << "年" << _month << "月" << _day << "日" << endl;
}

 运行下方代码:

int main()
{Date d1(2024, 1, 8);cout << d1;return 0;
}

此时仍然显示运行错误,但是将上方代码更改为下面的形式:

int main()
{Date d1(2024, 1, 8);/*cout << d1;*/d1 << cout;return 0;
}

代码成功运行,结果如下:

这是因为,对于双操作数的运算符,第一个参数是左操作数,第二个参数是右操作数,之前的文章中多次提到,对于成员函数来说,通常会有一个隐藏的参数,即this指针。所以,针对上面的运算符重载,其完整的参数应该为:

void Date::operator<<(Date* this, ostream& out)
{out << _year << "年" << _month << "月" << _day << "日" << endl;
}

所以,这就解释了为社么上面打印自定义类型d1时,cout<<d1这种形式会造成编译错误,而d1<<cout可以正常运行的原因。虽然将代码改为上述形式后,可以正常使用运算符cout,但是,与平时利用cout的使用习惯不符,改进的方法将在下一小节中进行介绍

1.2 针对上述问题的解决方法:

    上面提到,造成问题的原因时因为成员函数会有一个隐藏的参数this,为了避免此问题,可以将运算符重载的声明放在类之外,即作为一个全局函数,而非一个成员函数。对于全局函数,没有隐藏的参数this,因此可以人为定义参数的顺序,即:
 

void operator<<(ostream& out, const Date& d)
{out << d._year << "年" << d._month << "月" << d._day << "日" << endl;
}

虽然解决了操作数的顺序问题,但是由于在运算符中,三个成员变量  _year, _month, _day会受到访问限定符private的影响。因此,还需要解决成员变量的访问问题。对于此问题的解决,文章给出一种方法:


1.2.1 通过创建友元函数来实现对私有变量的访问

实现方法只需要在类中加上友元函数即可,即:
 

friend void operator<<(ostream& out, const Date& d);

(注:对于友元的相关知识将在下一篇文章中进行介绍,本文中只给出使用方法)

在加入了友元函数后,上述的运算符重载即可正常进行使用,即:

int main()
{Date d1(2024, 1, 8);cout << d1;return 0;
}

运行结果如下:

对于流提取,采用和流插入一样的实现方法,即:
创建运算符重载:

void operator>>(istream& in,Date& dd)
{in >> dd._year >> dd._month >> dd._day;
}

 在类中加入友元函数:

friend void operator>>(istream& in, Date& dd);

测试流提取的功能:
 

int main()
{Date d1(2024, 1, 8);cin >> d1;cout << d1;return 0;
}

运行结果如下:

2. const成员函数:

2.1 const成员函数基本介绍:

文章在介绍刘运算符重载的时候举了一个例子,即创建一个对象,并且将其打印,即:

Date d1(2024, 1, 8);

在之前对于引用进行介绍的文章中,提到了常饮用这个概念,即在引用的前面加上const,如果在上面给出的自定义类型d1前加上const,再对这个自定义类型进行打印,即:
 

int main()
{const Date d3(2024, 1, 9);d3.Print();return 0;
}

运行代码,此时编译器会显示错误。

具体错误原因与成员函数的隐藏变量this以及权限变化有关。在常饮用那一节就提到过:权限平移或者缩小而不能放大,对于前面加了const的自定义类型d3,当d3向函数Print传递参数时,其参数类型为const \, Date*,而函数Printthis的类型为Date* this,因此,在传递参数的过程中,涉及了权限放大。对于此问题的解决方法需要在函数后面加上一个const

(注:如果函数的声明和定义分离,则在声明和定义后都需要加上const

//函数声明
void Print() const;
//函数定义
void Date::Print() const
{cout << "void Date::Print() const" << endl;cout << _year << " " << _month << " " << _day << endl;
}

运行结果如下:

上面提到,权限不能放大,但是可以缩小或者平移,因此,非const类型的变量可以调用const类型的函数,例如:

int main()
{Date d4(2222, 2, 22);d4.Print();return 0;
}

运行结果如下:

 

2.2 什么类型的函数需要加const

在日期类中,给了很多的关于运算符重载的例子,例如:                               

bool operator>(Date& d);

利用上述运算符对下面两个自定义类型变量进行比较,即:

int main()
{const Date d3(2024, 1, 9);d3.Print();Date d4(2222, 2, 22);d4.Print();bool ret1 = (d3 > d4);cout << ret1 << endl;return 0;
}

运行代码,此时编译器会报错。

错误原因依旧涉及权限放大的问题,通过两个自定义类型的传递参数的顺序可以发现,d3在传递参数时,也涉及了权限的放大,因此,也需要将上述函数进行更改,即:

bool operator>(Date& d)const;
bool Date::operator>(Date& d) const
{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;}else{return false;}
}

通过上面的两个例子可以看到,const类型的对象可以调用const类型函数,非const型的对象也可以调用const类型函数。因此,对于能够定义成const类型的成员函数,一般都需要加上const

前面的例子中,不难发现,在函数声明后面加上const的作用,主要是修饰*this,因此,如果一个成员函数涉及到对象的更改,则不能用const修饰。因此,对于日期类中的所有函数类型,可以加const的如下:

	bool operator==(Date& d)const;bool operator!=(Date& d)const;bool operator>(Date& d)const;bool operator>=(Date& d)const;bool operator<=(Date& d)const;bool operator<(Date& d)const;Date operator+(int day)const;Date operator-(int day)const;

需要注意,文章上面给出的流插入、流提取这两个函数由于不是成员函数,故不能用const修饰。

3.取地址及const取地址操作符重载:

       在前面的部分,介绍了默认成员函数中的4个,本部分将给出剩余的两个,由于这两个默认成员函数的实用意义远小于构造、析构、拷贝构造、赋值重载,因此文章只给出这两个函数的格式以及简单的应用:

      格式如下:

	//取地址操作符重载Date* operator&(){cout << "Date* operator&()" << endl;return this;}//const取地址操作符重载const Date* operator&() const{cout << "const Date* operator&() const" << endl;return this;}

       需要注意的时,这两个函数不光类型不同,其参数类型也不同,对于const取地址操作符重载,第一个const用于修饰函数的返回值,第二个const修饰的是*this。所以二者的参数类型不同。

下面给出测试代码来对取地址操作符重载以及const取地址操作符重载的调用进行演示:
 

const Date d3(2024, 1, 9);//d3.Print();Date d4(2222, 2, 22);//d4.Print();cout << &d3 << endl;cout << &d4 << endl;

运行结果如下:

        不难发现,自定义类型d3const修饰,因此优先调用const取地址操作符重载,自定义类型d4没有被const修饰,优先调用取地址操作符重载。 加入,在这两个函数中去掉一个,例如去掉取地址操作符重载,即:

//取地址操作符重载/*Date* operator&(){cout << "Date* operator&()" << endl;return this;}*///const取地址操作符重载const Date* operator&() const{cout << "const Date* operator&() const" << endl;return this;}

再运行下面的代码:

const Date d3(2024, 1, 9);//d3.Print();Date d4(2222, 2, 22);//d4.Print();cout << &d3 << endl;cout << &d4 << endl;

运行结果为:

当两个函数都去掉后,即:
 

	//取地址操作符重载/*Date* operator&(){cout << "Date* operator&()" << endl;return this;}*///const取地址操作符重载/*const Date* operator&() const{cout << "const Date* operator&() const" << endl;return this;}*/

再次运行下方代码:
 

cout << &d4 << endl;cout << &d3 << endl;

运行结果如下:

此时代码依旧正常运行。这是因为取地址操作符重载和const取地址操作符重载是默认构造函数,他的性质与构造函数类似,当不人为编写上述两个重载时,编译器会自动生成,当认为编写两个重载时,编译器会去调用已经编写好的。 

4. 勘误:

  由于个人能力有限,书中难免出现汉字拼写错误、代码意义解释错误、内容逻辑以及理解错误等不同类型的错误。首先感谢各位大佬能花掉自己宝贵的时间阅读此文章,愿大佬们斧正,发现错误可以通过私信联系,本人不胜感激。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/606784.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

李沐-《动手学深度学习》--03-注意力机制

一、注意力机制 1 . 注意力提示 1&#xff09;框架 **随意&#xff1a;**跟随自己的想法的&#xff0c;自主的想法&#xff0c;例如query **不随意&#xff1a;**没有任何偏向的选择&#xff0c;例如 Keys 如何得到 k v q 2&#xff09;Nadaraya-Watson核回归 就是一个so…

《2024 AIGC 应用层十大趋势白皮书》:近屿智能OJAC带您一起探索AI未来

Look&#xff01;&#x1f440;我们的大模型商业化落地产品&#x1f4d6;更多AI资讯请&#x1f449;&#x1f3fe;关注Free三天集训营助教在线为您火热答疑&#x1f469;&#x1f3fc;‍&#x1f3eb; 近日国际知名咨询机构IDC发布《2024 AIGC 应用层十大趋势白皮书》的发布&am…

Spring 动态数据源事务处理

在一般的 Spring 应用中,如果底层数据库访问采用的是 MyBatis,那么在大多数情况下,只使用一个单独的数据源,Spring 的事务管理在大多数情况下都是有效的。然而,在一些复杂的业务场景下,如需要在某一时刻访问不同的数据库,由于 Spring 对于事务管理实现的方式,可能不能达…

二叉树OJ练习(二)

1. 二叉树的最近公共祖先 题目描述&#xff1a; ​ 题解: 1.p或者q其中一个等于root&#xff0c;那么root就是最进公共祖先 2.p和q分布在root的左右两侧&#xff0c;那么root就是最进公共祖先 3.p和q在root的同一侧&#xff0c;就是要遍历这棵树&#xff0c;遇到p或者q返回 ​…

一款好的葡萄酒关键在哪里?

除了易于种植&#xff0c;赤霞珠还因其独特的口感、难以置信的味道和质量而闻名。这种葡萄主要用于中高端干红葡萄酒&#xff0c;通常表现出成熟的黑色水果味道&#xff0c;带有辛辣和泥土气息。 在橡木桶中陈酿后&#xff0c;赤霞珠表现极佳。随着葡萄酒的陈年&#xff0c;橡木…

【金猿人物展】数元灵科技CEO朱亚东:何以数智化

‍ 朱亚东 本文由数元灵科技CEO朱亚东撰写并投递参与“数据猿年度金猿策划活动——2023大数据产业年度趋势人物榜单及奖项”评选。 大数据产业创新服务媒体 ——聚焦数据 改变商业 在大数据经济的高速发展下&#xff0c;数据已经成为第5生产要素。打造以数据驱动为中心的标准化…

腾讯云免费服务器申请1个月攻略,亲测可行教程

腾讯云免费服务器申请入口 https://curl.qcloud.com/FJhqoVDP 免费服务器可选轻量应用服务器和云服务器CVM&#xff0c;轻量配置可选2核2G3M、2核8G7M和4核8G12M&#xff0c;CVM云服务器可选2核2G3M和2核4G3M配置&#xff0c;腾讯云服务器网txyfwq.com分享2024年最新腾讯云免费…

NUXT3学习笔记

1.邂逅SPA、SSR 1.1 单页面应用程序 单页应用程序 (SPA) 全称是&#xff1a;Single-page application&#xff0c;SPA应用是在客户端呈现的&#xff08;术语称&#xff1a;CSR&#xff08;Client Side Render&#xff09;&#xff09; SPA的优点 只需加载一次 SPA应用程序只需…

(二)Explain使用与详解

explain中的列 sql语句: EXPLAIN SELECT * from user WHERE userId=1340; 执行结果: 1. id列 id列的编号是 select 的序列号,有几个 select 就有几个id,并且id的顺序是按 select 出现的顺序增长的。 id列越大执行优先级越高,id相同则从上往下执行,id为NULL最后执行…

Chrome您的连接不是私密连接或专用连接

方法一&#xff1a; 在当前页面用键盘输入 thisisunsafe &#xff0c;不是在地址栏输入&#xff0c;就直接敲键盘就行了因为Chrome不信任这些自签名ssl证书&#xff0c;为了安全起见&#xff0c;直接禁止访问了&#xff0c;thisisunsafe 这个命令&#xff0c;说明你已经了解并…

富文本编辑器

富文本&#xff1a;带样式&#xff0c;多格式的文本&#xff0c;在前端一般使用标签配合内联样式实现 富文本编辑器&#xff08;Rich Text Editor&#xff0c;简称 RTE&#xff09;是一种用户可以使用来创建格式化的文本内容的界面组件。它通常可以嵌入到网页或应用程序中&…

Stm32cube keil5配置串口printf 蓝牙打印不出来

1.检查cube里面波特率是否与AT蓝牙设置一致 2.keil里面设置是否打开Use MicroLIB 3、stm32cube是否开启串口中断 4.检测线路是否接触不良&#xff0c;读写线插反等。

IO流-文件复制

IO流 概述&#xff1a;IO流&#xff0c;输入输出流&#xff08;Input Output&#xff09;流&#xff1a;一种抽象的概念&#xff0c;对数据传输的总称。&#xff08;数据在设备之间的传输称为流&#xff09;常见的功能 文件复制文件上传文件下载 学习流&#xff0c;我们要搞懂…

拓数派加入 OpenCloudOS 操作系统开源社区,作为成员单位参与社区共建

近日&#xff0c;拓数派签署 CLA(Contributor License Agreement 贡献者许可协议)&#xff0c;正式加入 OpenCloudOS 操作系统开源社区。 拓数派&#xff08;英文名称“OpenPie”&#xff09;是国内基础数据计算领域的高科技创新企业。作为国内云上数据库和数据计算领域的引领者…

云渲染适合什么场景下使用?

云渲染作为影视动画主流的渲染方案&#xff0c;通常云渲染服务商拥有专属的渲染农场&#xff0c;通过渲染农场庞大的高新能数量机器&#xff0c;可协助你在短时间内完成渲染任务。 云渲染使用场景有哪些&#xff1f; 1、硬件限制&#xff1a; 如果你的个人或公司电脑硬件不足…

大模型第三节课程笔记

大模型开发范式 优点&#xff1a;具有强大语言理解&#xff0c;指令跟随&#xff0c;和语言生成的能力&#xff0c;具有强大的知识储备和一定的逻辑推理能力&#xff0c;进而能作为基座模型&#xff0c;支持多元应用。 不足&#xff1a;大模型的知识时效性受限&#xff0c;大模…

【系统高级-环境变量】path配置一整行,而不是列表

这是列表编辑方便。但是不知道为什么变成一行&#xff0c;非常的令人抓狂&#xff0c;经过研究发现&#xff0c;第一个环境变量必须为C:\Windows\system32 开头才可以 文章如下 修改环境变量中的一行变成列表形式_环境变量编辑不是列表-CSDN博客

DDIM学习笔记

写在前面&#xff1a; &#xff08;1&#xff09;建议看这篇论文之前&#xff0c;可先看我写的前一篇论文&#xff1a; DDPM推导笔记-大白话推导 主要学习和参考了以下文章&#xff1a; &#xff08;1&#xff09;一文带你看懂DDPM和DDIM &#xff08;2&#xff09;关于 DDIM …

音频文件元数据:批量修改技巧,视频剪辑高效修改元数据的方法

随着数字媒体技术的快速发展&#xff0c;音频文件已成为日常生活中的重要组成部分。无论是音乐、语音还是其他音频内容&#xff0c;元数据都是描述这些文件的重要信息。下面来看下云炫AI智剪如何批量修改音频文件元数据&#xff0c;在视频剪辑中高效修改元数据的方法。 下面来看…

Java常用类---包装类

包装类 包装类简介 Java语言是典型的面向对象编程语言&#xff0c;但是其中的8种基本数据类型并不支持面向对象编程&#xff0c;基本类型数据不具备"对象"的特性&#xff0c;即&#xff1a;没有携带属性以及没有方法可以调用。 为了解决上述问题&#xff0c;java为…