C++类和对象终章——友元函数 | 友元类 | 内部类 | 匿名对象 | 关于拷贝对象时一些编译器优化


文章目录
- 💐专栏导读
- 💐文章导读
- 🌷友元
- 🌺概念
- 🌺友元函数
- 🍁友元函数的重要性质
- 🌺友元类
- 🍁友元类的重要性质
- 🌷内部类(不常用)
- 🌺内部类的性质
- 🌷匿名对象
- 🌷关于拷贝对象时一些编译器优化
💐专栏导读
🌸作者简介:花想云,在读本科生一枚,致力于 C/C++、Linux 学习。
🌸本文收录于 C++系列,本专栏主要内容为 C++ 初阶、C++ 进阶、STL 详解等,专为大学生打造全套 C++ 学习教程,持续更新!
🌸相关专栏推荐:C语言初阶系列 、C语言进阶系列 、数据结构与算法
💐文章导读
本文为类和对象终章,我们将学习友元的概念,包含友元函数和友元类;内部类;匿名对象以及关于拷贝构造时一些编译器优化的情况等。
🌷友元
面向对象有三大特性——封装、继承、多态。从学习C++至今,我们一直在谈封装的重要性。但是在某些特殊的情况下,有时需要突破封装的限制。
🌼举例
之前我们通过实现日期类来学习运算符重载。其中实现操作符<<(流插入)、>>(流提取)的重载时,我们遇到了难题——如果在类中实现<<>>重载,我们无法调换this指针的位置,导致实现出来的重载<<用起来怪怪的。如下:
class Date
{
//...//使用因为返回,为了适应连续输入或输出的情况ostream& operator<<(ostream& out){out << _year << "年" << _month << "月" << _day << "日" << endl;return out;}istream& operator>>(istream& in){in >>_year >>_month >>_day;return in;}//...
}
void Test()
{Date d1(2023, 4, 1);d1 << cout;//有点奇怪
}
还记得当时我们是怎么解决的吗?答案是,可以将两个函数改为友元函数。例如:
class Date
{
//...//声明友元函数friend ostream& operator<<(ostream& out, const Date& d);friend istream& operator>>(istream& in, Date& d);//...
}
ostream& operator<<(ostream& out, const Date& d)
{out << d._year << "年" << d._month << "月" << d._day << "日";return out;
}istream& operator>>(istream& in, Date& d)
{in >> d._year >> d._month >> d._day;return in;
}
上次我们只是浅浅的看了一下友元函数的使用。今天我们正式认识一下友元。
🌺概念
友元提供了一种突破封装的方式,有时提供了便利。但是友元会增加耦合度,破坏了封装,所以友元不宜多用。
友元分为:友元函数和友元类。
🌺友元函数
友元函数可以直接访问类的私有成员,它是定义在类外部的普通函数,不属于任何类,但需要在类的内部声明,声明时需要加friend关键字。
🌼示例
{
//...//声明友元函数friend ostream& operator<<(ostream& out, const Date& d);friend istream& operator>>(istream& in, Date& d);//...
}
ostream& operator<<(ostream& out, const Date& d)
{out << d._year << "年" << d._month << "月" << d._day << "日";return out;
}istream& operator>>(istream& in, Date& d)
{in >> d._year >> d._month >> d._day;return in;
}
🍁友元函数的重要性质
友元函数有如下几条重要的性质:
- 友元函数可访问类的私有和保护成员,但它不是类的成员函数;
- 友元函数不能用
const修饰; - 友元函数可以在类定义的
任何地方声明,不受类访问限定符限制; 一个函数可以是多个类的友元函数;- 友元函数的调用与普通函数的调用原理相同;
🌺友元类
友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非公有成员。
🌼示例
class Time
{friend class Date;//声明日期类为时间类的友元类,则在日期类中可以直接发访问时间类Time(int hour = 0, int minute = 0, int second = 0): _hour(hour), _minute(minute), _second(second){}
private:int _hour;int _minute;int _second;
};
class Date
{
public:Date(int year = 2023, int month = 4, int day = 9): _year(year), _month(month), _day(day){}void SetTime(int hour, int minute, int second){// 直接访问时间类私有的成员变量_t._hour = hour;_t._minute = minute;_t._second = second;}
private:int _year;int _month;int _day;Time _t;
};
🍁友元类的重要性质
友元类的重要性质如下:
友元关系是单向的,不具有交换性。
比如上述Time类和Date类,在Time类中声明Date类为其友元类,那么可以在Date类中直接访问Time类的私有成员变量,但想在Time类中访问Date类中私有的成员变量则不行。
友元关系不能传递;
如果C是B的友元, B是A的友元,则不能说明C是A的友元。
友元关系不能继承(先不做解释);
🌷内部类(不常用)
如果一个类定义在另一个类的内部,这个类就叫做内部类。内部类是一个独立的类,它不属于外部类,更不能通过外部类的对象去访问内部类的成员。外部类对内部类没有任何优越的访问权限。
内部类有一个重要的性质——内部类天生就是外部类的友元。参照友元类的定义,内部类可以通过外部类的对象参数来访问外部类中的所有成员。但是外部类不是内部类的友元。
🌺内部类的性质
- 内部类可以定义在外部类的
public、protected、private下。 - 注意内部类可以直接访问外部类中的
static成员,不需要外部类的对象或类名。 sizeof(外部类)=外部类,说明外部类和内部类在空间上没有任何关系。
🌼示例
class A
{
private://声明static成员static int k;int n=0;
public:class B // B天生就是A的友元{public:void print(const A& a){cout << k << endl;cout << a.n << endl;}};
};//初始化static成员
int A::k = 1;int main()
{A::B b;//定义B类对象A a;b.print(a);return 0;
}
🌷匿名对象
匿名对象,顾名思义,该对象没有名字就叫匿名对象。匿名对象重要的性质:
匿名对象的生命周期只在定义它的那一行;
🌼示例
class A
{
public:A(int a = 0):_a(a){}
private:int _a;
};int main()
{//普通对象A a1;//匿名对象的定义return 0;
}
匿名对象看似鸡肋,但在某些场合下非常适用。比如,我们只想拿到类内部的某个成员的值,或只是想用一下类中的某个成员函数,为了一件简单的事而专门定义一个对象再销毁显得有点多此一举,那么就可以使用匿名对象。
🌼示例
class solution
{
public:int Sum_Solution(int n){int sum = 0;for (int i = 1; i <= n; i++){sum += i;}return sum;}
};
int main()
{//匿名对象的使用场景cout << solution().Sum_Solution(100) << endl;return 0;
}

🌷关于拷贝对象时一些编译器优化
对于有些场景下,若出现拷贝构造与构造同时出现的情况,编译器可能省略中间的拷贝构造,转化为直接构造。(此种情况取决于不同编译器不同的实现方法)
🌼示例
上一章中,我们谈到类型转换。这是典型的1个拷贝构造+1个构造优化为——>直接构造。
class Date
{
public:Date(int year):_year(year){}
private:int _year=0;
};void Test()
{//1个拷贝构造+1个构造优化为——>直接构造Date d2 = 2023;
}
🌼其它情况
class A
{
public:A(int a = 0):_a(a){}
private:int _a;
};void func1(A aa)
{}void func2(const A& aa)
{}A func3()
{A aa;return aa;
}A func4()
{return A();
}int main()
{A aa1 = 1; // 构造+拷贝构造 ——> 优化为直接构造func1(aa1); // 无优化func1(2); // 构造+拷贝构造 ——> 优化为直接构造func1(A(3)); // 构造+拷贝构造——> 优化为直接构造func2(aa1); // 无优化func2(2); // 无优化func2(A(3)); // 无优化A aa1 = func3(); // 拷贝构造+拷贝构造 -- 优化为一个拷贝构造A aa2;aa2 = func3(); // 不能优化func4(); // 构造+拷贝构造 -- 优化为直接构造A aa3 = func4(); // 构造+拷贝构造+拷贝构造 -- 优化为直接构造return 0;
}

点击下方个人名片,可添加博主的个人QQ,交流会更方便哦~
↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
相关文章:
C++类和对象终章——友元函数 | 友元类 | 内部类 | 匿名对象 | 关于拷贝对象时一些编译器优化
文章目录💐专栏导读💐文章导读🌷友元🌺概念🌺友元函数🍁友元函数的重要性质🌺友元类🍁友元类的重要性质🌷内部类(不常用)🌺内部类的性…...
拼多多按关键字搜索商品 API
一、拼多多平台优势: 1、独创拼团模式 拼团拼单是拼多多独创的营销模式,其特点是基于人脉社交的裂变传播,非常具有传播性。 由于本身走低价路线,加上拼单折扣,商品的分享和人群裂变效果非常明显,电商前期…...
全链路日志追踪
背景 最近线上的日志全局追踪 traceId 不好使了,不同请求经常出现重复的 traceId,或者通过某个请求的 traceId 追踪搜索,检索出了与该请求完全不相干的日志。我领导叫我去排查解决这个问题,这里我把我排查的过程思路以及如何解决…...
ZYNQ:【1】深入理解PS端的TTC定时器(Part1:原理+官方案例讲解)
碎碎念:好久不见,甚是想念!本期带来的是有关ZYNQ7020的内容,我们知道ZYNQ作为一款具有硬核的SOC,PS端很强大,可以更加便捷地实现一些算法验证。本文具体讲解一下里面的TTC定时器,之后发布的Part…...
蓝牙设备如何自定义UUID
如何自定义UUID 所有 BLE 自定义服务和特性必须使用 128 位 UUID 来识别,并且要确保基本 UUID 与 BLE 定义的基本 UUID(00000000-0000-1000-8000-00805F9B34FB)不一样。基本 UUID 是一个 128 位的数值,根据该值可定义标准UUID&am…...
好看的html登录界面,
界面效果: 代码: <!DOCTYPE html> <html><head><title>Login Page</title><style>body {background-color: #f2f2f2;font-family: Arial, sans-serif;}form {background-color: #fff;border-radius: 5px;box-shado…...
Java模拟星空
目录 前言 JavaFX基础 1. GraphicsContext 2. AnimationTimer 代码实现 完整代码 前言 看了Python模拟星空很漂亮,Java也应该必须有一个! 环境:只需要JDK1.8就好!不需要外部包!!! Jav…...
YGG 代表 Web3 Gaming 参加 2023 年游戏开发者大会
Yield Guild Games(YGG)在 2023 年 3 月 20 日至 24 日在加州旧金山举行的游戏开发者大会(GDC)上大显身手,这是游戏开发者的重要交流学习活动。虽然 GDC 本身提供了多种多样的活动,包括讲座、小组讨论、圆桌…...
水库安全运行智慧管理平台解决方案筑牢防汛“安全墙”
解决方案 水库安全运行智慧管理系统解决方案,系统主要由降雨量监测站、水库水位监测站、大坝安全监测中的渗流量、渗流压力和变形监测站及视频和图像监测站等站点组成,同时建立规范、统一的监测平台,集数据传输、信息共享、数据储存于一体&a…...
Exchange升级部署方案
目录 前言 一、需求分析 二、升级前准备 1.备份当前 Exchange Server 数据...
AE开发之图层渲染20210603
AE开发之图层渲染比例符号化地图的整饰唯一值符号的符号化过程点符号设置,线符号设置标注图层,(写得不好,不推荐看) 唯一值符号化,字段进行设置,这里用到了UniqueValueRenderer接口,这里面有一…...
需要了解的过滤器
过滤器 1. 概念 过滤器: 从名字上理解就是对于事件的过滤操作,在web 中的过滤器,就是对于请求进行过滤操作,我们使用过滤器,就可以对于请求进行拦截操作,然后进行响应的处理操作,实现很多的特殊…...
VUE3的setup函数
文章目录 目录 文章目录 前言 一、setup函数是什么? 二、使用步骤 三、vue3中文文档和面向vue3的组件库 总结 前言 Vue3是一个面向数据驱动的渐进式JavaScript框架,其的设计理念包括简洁、灵活和高效。相比Vue2,Vue3的架构设计有很大的不同&…...
停车场管理系统文件录入(C++版)
❤️作者主页:微凉秋意 ✅作者简介:后端领域优质创作者🏆,CSDN内容合伙人🏆,阿里云专家博主🏆 文章目录一、案例需求描述1.1、汽车信息模块1.2、普通用户模块1.3、管理员用户模块二、案例分析三…...
线程(Thread)的三种等待唤醒机制详解
1、为什么需要线程的等待和唤醒 线程的等待唤醒机制是一种经典的“生产者和消费者”模型。例如食品加工厂,食品加工人员和原料补给人员,在有充足原料时,补给人员是在等待,等到原料不够时,食品加工人员通知补给人员&am…...
从零学习python - 13模块的导入与使用(实现单例模式)
模块基础知识 # 项目 > 包 > 模块 > 变量\方法\类 # 在python中,模块是代码组织的一种方式,把功能相近的函数或类放到一个文件中,一个文件(.py)就是一个模块,模块名就是文件名去掉py后缀. # 好处:提高代码可复用性和可维护性,一个模块编写完成后,很方便在其他项目中导…...
国产SSD、内存卷哭国外大厂,三星宣布减产涨价在路上了
PC 圈有一句话是这么说的:论价格屠夫还得看国产品牌! 可不是嘛,国产长鑫、长江算是彻底将全球存储芯片市场搅局者这一「骂名」坐实了! 不说特别早期,前几年吧,普通单条 8G DDR4 内存都能卖到六七百元&…...
数据库管理-第六十六期 SQL Domain(20230413)
数据库管理 2023-04-13第六十六期 SQL Domain1 基本介绍2 Domain的表达式和条件3 语法4 语义5 示例总结第六十六期 SQL Domain 上一期一笔带过了部分Oracle 23c的新特性,这一期重点讲一下SQL Domain新特性。 【https://docs.oracle.com/en/database/oracle/oracle-…...
《Vue3实战》 第一章 nods/npm安装、配置
1、nods.js安装(Windows) 1.1、下载并安装node https://nodejs.org/en/ , 安装到d盘nodejs目录 1.2、配置环境变量 path配置 1.3、配置全局包存放目录和缓存目录 在根目录下创建node_global(全局包存放目录)和node_cache&…...
JAVA练习104-四数相加 II
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 目录 前言 一、题目-四数相加 II 1.题目描述 2.思路与代码 2.1 思路 2.2 代码 总结 前言 提示:这里可以添加本文要记录的大概内容: 4月10日练…...
PT 助手 Plus:全方位提升 PT 站点种子下载体验
PT 助手 Plus:全方位提升 PT 站点种子下载体验 【免费下载链接】PT-Plugin-Plus PT 助手 Plus,为 Microsoft Edge、Google Chrome、Firefox 浏览器插件(Web Extensions),主要用于辅助下载 PT 站的种子。 项目地址: h…...
可视化是对比原始数据和填补数据的强大工具。你可以使用箱线图、密度图或散点图来可视化原始数据和填补后的数据
下面的内容摘录自《用R探索医药数据科学》专栏文章的部分内容(原文5665字)。 2篇2章6节:R的多重填补法中随机回归填补法的应用,MICE包的实际应用和统计与可视化评估-CSDN博客 在数据分析中,缺失数据是常见且具有挑战性…...
告别公网IP和路由器设置:用cpolar免费隧道实现Home Assistant外网控制
零门槛实现Home Assistant远程控制:无需公网IP的内网穿透方案 想象一下这样的场景:你正躺在异国酒店的床上,突然想起出门前忘记关闭客厅的智能灯。或者,你在公司加班时,想提前打开家中的空调。对于智能家居爱好者来说&…...
数据库索引优化与慢查询排查实战:1000名工人工单工单系统性能攻坚
数据库索引优化与慢查询排查实战:千人施工队工单系统性能攻坚场景:某建筑集团大型商业综合体项目 规模:1000名工人,日均生成3000工单,工单表累计800万记录 痛点:早班派工高峰期系统卡顿,工单查询…...
遥感影像裁剪避坑指南:如何用ENVI5.3的Subset功能精准提取县区数据(含背景值设置技巧)
遥感影像裁剪避坑指南:ENVI5.3 Subset功能深度解析与实战技巧 当你在处理县域尺度的遥感影像分析时,是否遇到过裁剪后图像边缘出现黑边、数据丢失或坐标错位的问题?这些看似简单的操作细节,往往成为影响后续分析精度的关键因素。本…...
FGSM对抗攻击实战:从理论到PyTorch代码的完整攻防演练
1. 对抗攻击入门:为什么你的AI模型会被"骗"? 想象一下,你训练了一个准确率高达99%的手写数字识别模型,但在实际应用中却发现它经常把"3"识别成"8",把"6"识别成"0"。…...
Clawdbot汉化版开源可部署:MIT协议+全栈TypeScript+模块化Agent设计解析
Clawdbot汉化版开源可部署:MIT协议全栈TypeScript模块化Agent设计解析 1. 项目概述与技术特色 Clawdbot是一个开源的智能对话助手系统,采用MIT协议发布,允许用户自由使用、修改和分发。这个项目的核心价值在于让用户能够在主流即时通讯平台…...
如何在Linux内核中实现高性能exFAT文件系统读写支持?
如何在Linux内核中实现高性能exFAT文件系统读写支持? 【免费下载链接】exfat-nofuse Android ARM Linux non-fuse read/write kernel driver for exFat and VFat Android file systems 项目地址: https://gitcode.com/gh_mirrors/ex/exfat-nofuse 你是否曾经…...
springboot-vue+nodejs的公考在线刷题学习平台的设计与实现
目录技术栈选择核心模块设计关键实现步骤扩展功能建议示例代码片段(Spring Boot Controller)注意事项项目技术支持源码获取详细视频演示 :文章底部获取博主联系方式!同行可合作技术栈选择 后端框架:Spring Boot&#…...
深入解析SD卡CMD指令集:从寄存器操作到数据传输实战
1. SD卡基础寄存器全解析 当你把一张SD卡插入读卡器时,系统瞬间就能识别出容量和型号,这个过程背后其实是SD卡内部寄存器的功劳。这些寄存器就像SD卡的"身份证"和"体检报告",存储着所有关键信息。我刚开始接触嵌入式开发…...
