【C++初阶】友元(友元函数友元类)、内部类、匿名对象、拷贝对象时的优化

news/2024/5/17 12:42:01/文章来源:https://blog.csdn.net/Captain_ldx/article/details/128070069

🌟hello,各位读者大大们你们好呀🌟

🍭🍭系列专栏:【C++学习与应用】

✒️✒️本篇内容:友元函数和友元类的概念和基础应用,简单介绍内部类、匿名对象、拷贝对象时的部分编译器优化情况

🚢🚢作者简介:计算机海洋的新进船长一枚,请多多指教( •̀֊•́ ) ̖́-

📡📡同期文章:【C++初阶】初始化列表、static成员(静态成员变量 & 静态成员函数)

目录

一、友元

1.友元函数

(1)友元函数的引出

(2)友元函数的说明 

2.友元类

二、内部类

三、匿名对象

四、拷贝对象时的部分编译器优化情况


一、友元

友元提供了一种突破封装的方式,有时提供了便利。但是友元会增加耦合度,破坏了封装,所以友元不宜多用。友元分为:友元函数和友元类。 

1.友元函数

(1)友元函数的引出

问题:现在尝试去重载operator<<,然后发现没办法将operator<<重载成成员函数。

因为cout的输出流对象和隐含的this指针在抢占第一个参数的位置。this指针默认是第一个参数也就是左操作了。但是实际使用中cout需要是第一个形参对象,才能正常使用。所以要将operator<<重载成全局函数。但又会导致类外没办法访问成员,此时就需要友元来解决。operator>>同理。

class Date
{
public:Date(int year, int month, int day): _year(year), _month(month), _day(day){}// d1 << cout; -> d1.operator<<(&d1, cout); 不符合常规调用
// 因为成员函数第一个参数一定是隐藏的this,所以d1必须放在<<的左侧
ostream& operator<<(ostream& _cout)
{_cout << _year << "-" << _month << "-" << _day << endl;return _cout;
}
private:int _year;int _month;int _day;
};

友元函数可以直接访问类的私有成员,它是定义在类外部普通函数,不属于任何类,但需要在类的内部声明,声明时需要加 friend 关键字。

class Date
{friend ostream& operator<<(ostream& _cout, const Date& d);friend istream& operator>>(istream& _cin, Date& d);
public:Date(int year = 1900, int month = 1, int day = 1): _year(year), _month(month), _day(day){}
private:int _year;int _month;int _day;
};
ostream& operator<<(ostream& _cout, const Date& d)
{_cout << d._year << "-" << d._month << "-" << d._day;return _cout;
}
istream& operator>>(istream& _cin, Date& d)
{_cin >> d._year;_cin >> d._month;_cin >> d._day;return _cin;
}
int main()
{Date d;cin >> d;cout << d << endl;return 0;
}

(2)友元函数的说明 

  • 友元函数可访问类的私有和保护成员,但不是类的成员函数
  • 友元函数不能用const修饰
  • 友元函数可以在类定义的任何地方声明,不受类访问限定符限制(可访问private)
  • 一个函数可以是多个类的友元函数
  • 友元函数的调用与普通函数的调用原理相同

2.友元类

友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非公有成员。

  • 友元关系是单向的,不具有交换性。

比如下述Time类和Date类,在Time类中声明Date类为其友元类,那么可以在Date类中直接访问Time类的私有成员变量,但想在Time类中访问Date类中私有的成员变量则不行。

  • 友元关系不能传递如果C是B的友元

B是A的友元,则不能说明C时A的友元。

  • 友元关系不能继承,在继承位置再给大家详细介绍。

理解上有问题,没关系,直接上代码

class Time
{friend class Date;   // 声明日期类为时间类的友元类,则在日期类中就直接访问Time类中的私有成员变量
public: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 = 1900, int month = 1, int day = 1): _year(year), _month(month), _day(day){}void SetTimeOfDate(int hour, int minute, int second){// 直接访问时间类私有的成员变量_t._hour = hour;_t._minute = minute;_t._second = second;}private:int _year;int _month;int _day;Time _t;
};


二、内部类

概念如果一个类定义在另一个类的内部,这个内部类就叫做内部类。内部类是一个独立的类,它不属于外部类,更不能通过外部类的对象去访问内部类的成员。外部类对内部类没有任何优越的访问权限。

注意内部类就是外部类的友元类,参见友元类的定义,内部类可以通过外部类的对象参数来访
问外部类中的所有成员。但是外部类不是内部类的友元。

特性

  1. 内部类可以定义在外部类的public、protected、private都是可以的。
  2. 注意内部类可以直接访问外部类中的static成员,不需要外部类的对象/类名。
  3. sizeof(外部类)=外部类,和内部类没有任何关系
class A
{
public:class B // B天生就是A的友元{public:void function(const A& a){cout << k << endl;//OKcout << a.h << endl;//OK}};
private:static int k;int h;
};
int A::k = 1;int main()
{A::B b;//使用上要注意b.function(A());return 0;
}


三、匿名对象

下面我们一起来看一段长代码来理解匿名对象的含义和作用,我们可以直接从 main() 看起

class A
{
public:A(int a = 0):_a(a){cout << "A(int a)" << endl;}~A()//析构函数{cout << "~A()" << endl;}
private:int _a;
};
class Solution {
public:int Sum_Solution(int n) {//...return n;}
};
int main()
{A aa1;// 不能像下面这样定义对象,因为编译器无法识别下面是一个函数声明,还是对象定义//A aa1();// 但是我们可以这么定义匿名对象,匿名对象的特点不用取名字,// 但是他的生命周期只有这一行,下一行他就会自动调用析构函数A();A aa2(2);//在()中加上数值,就可以让编译器识别出它是对象定义// 匿名对象在这样场景下就很好用 - 两行代码优化成一行直接构造//Solution aa3;//aa3.Sum_Solution(10);Solution().Sum_Solution(10);return 0;
}


四、拷贝对象时的部分编译器优化情况

在传参和传返回值的过程中,一般编译器会做一些优化,减少对象的拷贝,这个在一些场景下还是非常有用的。

class A
{
public:A(int a = 0)//构造函数:_a(a){cout << "A(int a)" << endl;}A(const A& aa)//拷贝构造:_a(aa._a){cout << "A(const A& aa)" << endl;}A& operator=(const A& aa)//运算符重载{cout << "A& operator=(const A& aa)" << endl;if (this != &aa){_a = aa._a;}return *this;}~A()//析构函数{cout << "~A()" << endl;}
private:int _a;
};
void f1(A aa)
{}
A f2()
{A aa;return aa;
}
int main()
{// 传值传参A aa1;f1(aa1);cout << endl;// 传值返回f2();cout << endl;// 隐式类型,连续构造+拷贝构造->优化为直接构造f1(1);// 一个表达式中,连续构造+拷贝构造->优化为一个构造f1(A(2));cout << endl;// 一个表达式中,连续拷贝构造+拷贝构造->优化一个拷贝构造A aa2 = f2();cout << endl;// 一个表达式中,连续拷贝构造+赋值重载->无法优化aa1 = f2();cout << endl;return 0;
}


🌹🌹友元(友元函数&友元类)、内部类、匿名对象、拷贝对象时的优化的知识大概就讲到这里啦,博主后续会继续更新更多C++的相关知识,干货满满,如果觉得博主写的还不错的话,希望各位小伙伴不要吝啬手中的三连哦!你们的支持是博主坚持创作的动力!💪💪 

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

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

相关文章

[第十二届蓝桥杯/java/算法]D——相乘

&#x1f9d1;‍&#x1f393;个人介绍&#xff1a;大二软件生&#xff0c;现学JAVA、Linux、MySQL、算法 &#x1f4bb;博客主页&#xff1a;渡过晚枫渡过晚枫 &#x1f453;系列专栏&#xff1a;[编程神域 C语言]&#xff0c;[java/初学者]&#xff0c;[蓝桥杯] &#x1f4d6…

还有1个月,乘用车搭载首超5百万辆!L2/L2+前装交付一路狂奔

高工智能汽车研究院监测数据显示&#xff0c;2022年1-11月中国市场&#xff08;不含进出口&#xff09;乘用车交付上险为1745.95万辆&#xff0c;同比上年同期下滑4.01%&#xff0c;降幅和1-10月数据相比&#xff0c;继续放大&#xff0c;显示市场回暖低于预期。 不过&#xff…

小学生C++编程基础 课程8(B)

919.3数排序 ( 课程8) 登录 920.求最小值 (课程8) 登录 921.排名 (课程8) 登录 922.中间数 ( 课程8&#xff09; 难度&#xff1a;1 登录 923.判断闰年 &#xff08;课程8&#xff09; 难度&#xff1a;1 登录 924.天数 (课程8) 难度&#xff1a;1 登录 《小学生C趣味编程…

c站top1全栈接口测试教程 postman接口测试 接口自动化测试全套教程

本文适合已经掌握 Postman 基本用法的读者&#xff0c;即对接口相关概念有一定了解、已经会使用 Postman 进行模拟请求等基本操作&#xff0c;文章末尾也搭配了相应的视频教程&#xff0c;如果喜欢的同学呢可以来个一键三连哈。 工作环境与版本&#xff1a; Window 7&#xff…

ERP外网访问,快解析助力企业远程办公

ERP系统是现代信息技术和先进管理经验的有效结合&#xff0c;实现对企业经营活动的自动、完整的记录&#xff0c;替代重复劳动&#xff0c;对企业人力资源、物流、资金流、票据流和信息流等的科学管理&#xff0c;实现业务管理数据和财务数据高度统一&#xff0c;实现对企业业务…

IB成绩换成GPA,美国大学是如何算的?

IB课程体系是全球公认的难度大、结构强的课程体系。 IB课程可以通过IB文凭课程&#xff08;也称为IBDP&#xff09;进行系统研究。IB课程体系是国际公认的基础文凭&#xff0c;世界上几乎所有大学都认可IB课程体系。这是否意味着IB在申请美国大学时会有优势&#xff1f; 事实上…

扫雷游戏的设计——大型程序的设计思路

目录 &#x1f33a;了解扫雷游戏的作用原理并梳理思路 &#x1f33a;扫雷游戏前期部分完善 &#x1f337;文件的创建 &#x1f337;创建菜单&#xff0c;完善主函数 &#x1f333;代码呈现&#xff1a; &#x1f33a;扫雷游戏主题内容 &#x1f335;第一步初始化棋盘 &#x1…

SpringBoot 基于 OAuth2 统一身份认证流程详解

1. 目标 了解OAUTH2统一认证基本概念了解OAUTH2协议流程了解OAUTH2各种模式类型了解Spring Security OAuth设计 2. 分析 传统登陆认证介绍 单点登陆认证介绍 OAuth2简介 OAuth2角色 OAuth2协议流程介绍 OAuth2授权类型 OAuth2授权码模式流程 OAuth2简化模式 OAuth2密码…

Canvas学习记录

Canvas学习基本用法1.首先得有canvas元素2.获取渲染上下文3.检查浏览器支持性4.例子绘制图形1.矩形2. 绘制路径3. 移动笔触4. 绘制直线5. 圆弧二次贝塞尔曲线与三次贝塞尔曲线Path2D 对象创建Path2D对象Path2D.addPath()使用样式和颜色色彩Colors透明度 Transparency线型 Line …

zabbix6.0安装教程(五):二进制包安装

zabbix6.0安装教程&#xff08;五&#xff09;&#xff1a;二进制包安装 目录一、使用ZABBIX官方存储库二、Red Hat zabbix企业版 Linux/CentOS1. 概述2. 安装注意事项2.1 使用 Timescale DB 导入数据2.2 PHP 7.22.3 配置 SELinux3. Proxy 安装3.1 创建数据库3.2 导入数据3.3 为…

【Java寒假打卡】Java基础-继承

【Java寒假打卡】Java基础-继承一、继承的好处和弊端二、继承的成员变量访问特点三、重写方法四、方法重写的注意事项五、权限修饰符六、构造方法一、继承的好处和弊端 继承的好处 提高了代码的复用性 提高了代码的维护性 让类和类之间产生了关系 是多态的前提 继承的弊端 …

刷爆力扣之字符串转换整数(atoi)

刷爆力扣之字符串转换整数(atoi) HELLO&#xff0c;各位看官大大好&#xff0c;我是阿呆 &#x1f648;&#x1f648;&#x1f648; 今天阿呆继续记录下力扣刷题过程&#xff0c;收录在专栏算法中 &#x1f61c;&#x1f61c;&#x1f61c; 该专栏按照不同类别标签进行刷题&a…

极海APM微控制器基于IAR开发环境搭建与工程调试配置方法

极海APM微控制器基于IAR开发环境搭建与工程调试配置方法✨本篇主要针对基于IAR for ARM版本&#xff1a;V9.30.1环境搭建和工程调试配置过程进行介绍&#xff0c;当然也同样适用于基于ARM架构芯片的开发使用。&#x1f4cc;相关资源内容引用&#xff1a;《最新版IAR9.30和注册工…

自动控制原理笔记-信号流图-Mason公式-控制系统的传递函数

目录 信号流图与结构图的比较&#xff1a; 掌握结构图与信号流图的转换&#xff1a; Mason增益公式&#xff1a; 式子详解&#xff1a; 使用Mason增益公式步骤&#xff1a; 使用Mason增益公式的例题&#xff1a; ​编辑 控制系统的传递函数 &#xff1a; 开环传递函数…

基于股票数据的k线图数据分析项目

图 完整代码: # pip install pandas -i https://pypi.tuna.tsinghua.edu.cn/simple import pandas as pd import seaborn as sns import numpy as np import matplotlib.pyplot as plt import warnings warnings.filterwarnings("ignore")#忽略一些警告 不影响运…

【实时数仓】DWS层的定位、DWS层之访客主题计算(PV、UV、跳出次数、计入页面数、连续访问时长)

文章目录一 DWS层与DWM层的设计1 设计思路2 需求梳理3 DWS层定位二 DWS层-访客主题计算1 需求分析与思路2 功能实现&#xff08;1&#xff09;封装VisitorStatsApp&#xff0c;读取Kafka各个流数据a 代码b 测试&#xff08;2&#xff09;合并数据流a 封装主题宽表实体类Visitor…

洛谷——P1573 栈的操作

文章目录栈的操作题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1提示AC代码栈的操作 题目描述 现在有四个栈&#xff0c;其中前三个为空&#xff0c;第四个栈从栈顶到栈底分别为 1,2,3,⋯,n1,2,3,\cdots ,n1,2,3,⋯,n。每一个栈只支持一种操作&#xff1a;弹出并压入…

路由器的工作原理(计算机网络-网络层)

目录 路由器的构成 转发和路由选择的区别 典型的路由器结构 交换结构 输出端口 路由器与交换机的比较 两种基于存储转发的分组交换设备的比较 交换机和路由器各有的应用场合 三层交换机 三层交换机的应用 路由器的构成 路由器的任务 路由器是一种具有多个输入端口和多…

【软件测试】那些35岁以上的测试人哪去了?

目录&#xff1a;导读前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09;前言 先根据大体年龄阶段…

Spring Boot全局异常处理器(原理及使用详解)

目录 1 什么是全局异常处理器 2 为什么需要全局异常 3 原理和目标 4 ControllerAdvice注解 4.1 Advice&#xff08;通知&#xff09; 4.2 ControllerAdvice结合方法型注解ExceptionHandler,用于捕获Controller中抛出的指定类型的异常&#xff0c;从而达到全局不同类型的异…