c++领域展开第九幕——类和对象(下篇收尾 友元函数、内部类、拷贝对象时的编译器优化)超详细!!!!

news2025/1/4 19:19:10

在这里插入图片描述

文章目录

  • 前言
  • 一、友元函数
  • 二、内部类
  • 三、匿名对象
  • 四、对象拷贝时的编译器优化
  • 总结

前言

上篇博客我们学习了类和对象后期的一些内容——初始化列表、类型转换、static成员
今天我们来对类和对象进行最后的收尾
开始发车啦

一、友元函数

• 友元提供了一种突破类访问限定符封装的方式,友元分为:友元函数和友元类在函数声明或类声明的前面加friend,并且把友元声明放到一个类的里面。
外部友元函数可访问类的私有和保护成员,友元函数仅仅是一种声明,他不是类的成员函数
• 友元函数可以在类定义的任何地方声明,不受类访问限定符限制。
• 一个函数可以是多个类的友元函数
• 友元类中的成员函数都可以是另一个类的友元函数,都可以访问另一个类中的私有和保护成员
• 友元类的关系是单向的,不具有交换性,比如A类是B类的友元,但是B类不是A类的友元。
• 友元类关系不能传递,如果A是B的友元, B是C的友元,但是A不是B的友元。
• 有时提供了便利。但是友元会增加耦合度破坏了封装,所以友元不宜多用

代码和文字更配嗷
在我的理解就是,友元函数方便了类里面的一些成员的访问,可以耦合两个类的成员的关系

#include<iostream>
using namespace std;
class B;
class A
{
	// 友元声明
	friend void func(const A& aa, const B& bb);
private:
	int _a1 = 1;
	int _a2 = 2;
};
class B
{
	// 友元声明
	friend void func(const A& aa, const B& bb);
private:
	int _b1 = 3;
	int _b2 = 4;
};
void func(const A& aa, const B& bb)
{
	cout << aa._a1 << endl;
	cout << bb._b1 << endl;
}
int main()
{
	A aa;
	B bb;
	func(aa, bb);
	return 0;
}
#include<iostream>
using namespace std;
class A
{
	// 友元声明
	friend class B;
private:
	int _a1 = 1;
	int _a2 = 2;
};
class B
{
public:
	void func1(const A& aa)
	{
		cout << aa._a1 << endl;
		cout << _b1 << endl;
	}
	void func2(const A& aa)
	{
		cout << aa._a2 << endl;
		cout << _b2 << endl;
	}
private:
	int _b1 = 3;
	int _b2 = 4;
};
int main()
{
	A aa;
	B bb;
	bb.func1(aa);
	bb.func1(aa);
	return 0;
}

二、内部类

• 如果一个类定义在另一个类的内部,这个内部类就叫做内部类内部类是一个独立的类,跟定义在全局相比,他只是受外部类类域限制和访问限定符限制,所以外部类定义的对象中不包含内部类
• 内部类默认是外部类的友元类
• 内部类本质也是一种封装,当A类跟B类紧密关联,A类实现出来主要就是给B类使用,那么可以考虑把A类设计为B的内部类,如果放到private/protected位置,那么A类就是B类的专属内部类,其他地方都用不了。

其实就跟命名空间域的套娃差不多

#include<iostream>
using namespace std;
class A
{
private:
	static int _k;
	int _h = 1;
public:
	class B // B默认就是A的友元
	{
	public:
		void foo(const A& a)
		{
			cout << _k << endl; //OK
			cout << a._h << endl; //OK
		}
	};
};
int A::_k = 1;
int main()
{
	cout << sizeof(A) << endl;
	A::B b;
	A aa;
	b.foo(aa);
	return 0;
}

这里有一个有意思的题目:求1+2+3+…+n
在这里插入图片描述
摆明了只能用类去处理,用到类和对象里面的构造函数
没有内部类之前,我们是这样,就是在构造函数这里做文章

class Sum
{
public:
	Sum()
	{
		_ret += _i;
		++_i;
	}
	static int GetRet()
	{
		return _ret;
	}
private:
	static int _i;
	static int _ret;
};
int Sum::_i = 1;
int Sum::_ret = 0;
class Solution 
{
public:
	int Sum_Solution(int n) 
	{
		// 变长数组
		Sum arr[n];
		return Sum::GetRet();
	}
};

有了内部类之后,还可以这么玩,好像有点意思哈

class Solution 
{
// 内部类
	class Sum
	{
	public:
		Sum()
		{
			_ret += _i;
			++_i;
		}
	};
static int _i;
static int _ret;
public:
	int Sum_Solution(int n) 
	{
		// 变长数组
		Sum arr[n];
		return _ret;
	}
};
int Solution::_i = 1;
int Solution::_ret = 0;

三、匿名对象

• 用 类型(实参) 定义出来的对象叫做匿名对象相比之前我们定义的 类型 对象名(实参) 定义出来的叫有名对象
• 匿名对象生命周期只在当前一行一般临时定义一个对象当前用一下即可,就可以定义匿名对象

使用场景比较少,这里看看代码理解 叭

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(1);
	A aa2(2);
	// 匿名对象在这样场景下就很好用,当然还有一些其他使用场景
	Solution().Sum_Solution(10);
	return 0;
}

四、对象拷贝时的编译器优化

• 现代编译器会为了尽可能提高程序的效率在不影响正确性的情况下会尽可能减少一些传参和传参过程中可以省略的拷贝。
• 如何优化C++标准并没有严格规定,各个编译器会根据情况自行处理。当前主流的相对新一点的编译器对于连续一个表达式步骤中的连续拷贝会进行合并优化,有些更新更"激进"的编译还会进行跨行跨表达式的合并优化

代码配图,绝不糊涂

#include<iostream>
using namespace std;
class A
{
public:
	A(int a = 0)
	:_a1(a)
	{
		cout << "A(int a)" << endl;
	}
	A(const A& aa)
	:_a1(aa._a1)
	{
		cout << "A(const A& aa)" << endl;
	}
	A& operator=(const A& aa)
	{
		cout << "A& operator=(const A& aa)" << endl;
		if (this != &aa)
		{
			_a1 = aa._a1;
		}
		return *this;
	}
	~A()
	{
		cout << "~A()" << endl;
	}
private:
	int _a1 = 1;
};
void f1(A aa)
{}
A f2()
{
	A aa;
	return aa;
}
int main()
{
	// 传值传参
	A aa1;
	f1(aa1);
	cout << endl;
	// 隐式类型,连续构造+拷贝构造->优化为直接构造
	f1(1);
	// 一个表达式中,连续构造+拷贝构造->优化为一个构造
	f1(A(2));
	cout << endl;

	// 传值返回
	// 返回时一个表达式中,连续拷贝构造+拷贝构造->优化一个拷贝构造 (vs2019)
	// 一些编译器会优化得更厉害,进行跨行合并优化,直接变为构造。(vs2022)
	f2();
	cout << endl;
	// 返回时一个表达式中,连续拷贝构造+拷贝构造->优化一个拷贝构造 (vs2019)
	// 一些编译器会优化得更厉害,进行跨行合并优化,直接变为构造。(vs2022)
	A aa2 = f2();
	cout << endl;
	// 一个表达式中,连续拷贝构造+赋值重载->无法优化
	aa1 = f2();
	cout << endl;
	return 0;
}

最原始的流程就是这样的,连续拷贝然后再赋值
在这里插入图片描述
后面慢慢进化是这样的,省略了中间的连续拷贝,优化成为一个构造
在这里插入图片描述
对象拷贝就到这里啦~~~

总结

今天就是把类和对象的收尾工作结束啦
友元函数的访问内部成员,内部类的套娃,拷贝对象的深究
基础的类和对象就到这里啦,小编下一篇将为大家带来新的内容

不要走开,小编持续更新中~~~~~

在这里插入图片描述

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

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

相关文章

LevelDB 源码阅读:利用 Clang 的静态线程安全分析

LevelDB 中有一些宏比较有意思&#xff0c;平时自己写代码的时候&#xff0c;还基本没用过。这些宏在 thread_annotations.h 中定义&#xff0c;可以在编译时使用 Clang 编译器的线程安全分析工具&#xff0c;来检测潜在的线程安全问题。 比如下面这些宏&#xff0c;到底有什么…

什么是实体完整性约束?

实体完整性约束是数据库设计中的一个核心概念&#xff0c;它确保了关系数据库中每个实体的唯一性和可标识性。以下是对实体完整性约束的详细解释&#xff1a; 一、定义 实体完整性约束是指关系的主关键字&#xff08;Primary Key&#xff09;不能重复&#xff0c;也不能取“空值…

OpenCV-Python实战(15)——像素直方图均衡画

一、像素均值与标准差 1.1 像素均值 cv2.mean() mean_val cv2.mean(img,mask*) mean_val&#xff1a;图像 BGR 通道的均值和透明度。 img&#xff1a;图像。 mask&#xff1a;可以选择是否添加掩膜&#xff0c;默认为&#xff1a;None。 import cv2 import numpy as npim…

推理加速:投机采样经典方法

一 SpecInfer 基于模型 SpecInfer&#xff08;[2305.09781] SpecInfer: Accelerating Generative Large Language Model Serving with Tree-based Speculative Inference and Verification&#xff09; SpecInfer 投机采样利用多个小型模型&#xff08;SSM&#xff09;快速生…

Docker学习相关笔记,持续更新

如何推送到Docker Hub仓库 在Docker Hub新建一个仓库&#xff0c;我的用户名是 leilifengxingmw&#xff0c;我建的仓库名是 hello_world。 在本地的仓库构建镜像&#xff0c;注意要加上用户名 docker build -t leilifengxingmw/hello_world:v1 .构建好以后&#xff0c;本地会…

数据挖掘——支持向量机分类器

数据挖掘——支持向量机分类器 支持向量机最小间隔面推导基于软间隔的C-SVM非线性SVM与核变换常用核函数 支持向量机 根据统计学习理论&#xff0c;学习机器的实际风险由经验风险值和置信范围值两部分组成。而基于经验风险最小化准则的学习方法只强调了训练样本的经验风险最小…

HTML——54. form元素属性

<!DOCTYPE html> <html><head><meta charset"UTF-8"><title>form元素属性</title></head><body><!--form标签用于创建一个表单&#xff0c;会将里面的内容一起发送服务器&#xff0c;结构类似于表格--><!-…

拓扑排序模板题:洛谷-家谱树

原题链接&#xff1a;B3644 【模板】拓扑排序 / 家谱树 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 题目&#xff1a; 题目描述 输入格式 输出格式 输入输出样例 思路&#xff1a; AC代码&#xff1a; 题目&#xff1a; 题目描述 有个人的家族很大&#xff0c;辈分…

JS实现SVG的TEXT标签自动换行功能

首先定义了一个RectAndText组件&#xff0c;这个组件实现了在矩形中显示居中的文本&#xff08;矩形可以根据自己需求要或者不要&#xff09; <template><rect :x"x" :y"y" :width"width" :height"height" :stroke"str…

网络安全 | 量子计算与网络安全:未来的威胁与机遇

网络安全 | 量子计算与网络安全&#xff1a;未来的威胁与机遇 一、前言二、量子计算对传统密码学的威胁2.1 量子计算原理概述2.2 量子计算破解密码的原理2.3 量子计算威胁的广泛影响 三、量子安全密码学&#xff1a;新的机遇3.1 量子安全密码学的研究方向3.2 量子安全密码学的安…

性能测试核心知识点 —— 负载模型!

性能测试是软件开发生命周期中非常重要的一环&#xff0c;通过对系统进行负载测试&#xff0c;可以评估系统在不同负载条件下的性能表现。而负载模型则是负载测试中的关键概念&#xff0c;它定义了测试的目标、策略、参数和流程&#xff0c;是进行性能测试的基础。 一、负载模型…

AURIX的TASKING链接文件语法学习

链接文件中的定义&#xff1a; group (ordered, contiguous, align 4, attributesrw, run_addr 0x70005000)//mem:dsram0){select ".data.user_test_data";select "(.data|.data*)";//select "(.bss|.bss*)"; //select ".bss.…

电脑dll文件丢失怎么恢复,丢失dll文件一键修复教程分享

动态链接库文件&#xff08;DLL&#xff09;是Windows操作系统中至关重要的组成部分&#xff0c;它们包含了许多程序运行所需的函数和资源。当电脑丢失DLL文件时&#xff0c;会导致软件无法正常运行&#xff0c;甚至影响系统的稳定性。本文将从多个角度全面分析解读电脑丢失DLL…

Vue项目整合与优化

前几篇文章&#xff0c;我们讲述了 Vue 项目构建的整体流程&#xff0c;从无到有的实现了单页和多页应用的功能配置&#xff0c;但在实现的过程中不乏一些可以整合的功能点及可行性的优化方案&#xff0c;就像大楼造完需要进行最后的项目验收改进一样&#xff0c;有待我们进一步…

面向机器学习的Java库与平台

学习Java语言中与机器学习相关的各种库与平台&#xff0c;了解每个库的功能&#xff0c;以及可以用它 们解决的问题。  实现机器学习应用时需要具备的Java环境  Weka&#xff1a;一个通用的机器学习平台  Java机器学习库&#xff1a;一系列机器学习算法  Apache Mah…

SAP SD学习笔记24 - 赠品的两种形式 - 内增Bonus数量、外增Bonus数量

上一章讲了无偿出荷的内容。 SAP SD学习笔记23 - 无偿出荷&#xff08;免费交货&#xff09;与继续无偿出荷&#xff08;继续免费交货&#xff09;-CSDN博客 本章继续将SAP中赠品的两种形式&#xff1a; - 内增Bonus数量&#xff1a;Bonus数量包含在总数量当中&#xff0c;比…

Python跨年烟花

目录 系列文章 写在前面 技术需求 完整代码 下载代码 代码分析 1. 程序初始化与显示设置 2. 烟花类 (Firework) 3. 粒子类 (Particle) 4. 痕迹类 (Trail) 5. 烟花更新与显示 6. 主函数 (fire) 7. 游戏循环 8. 总结 注意事项 写在后面 系列文章 序号直达链接爱…

深入理解MemCache

随着互联网应用的飞速发展&#xff0c;动态Web应用的性能问题逐渐成为开发者关注的焦点。其中&#xff0c;数据库作为系统性能的关键瓶颈&#xff0c;在用户请求量急剧增加的情况下&#xff0c;往往难以快速响应用户需求。为了解决这一问题&#xff0c;缓存技术应运而生。MemCa…

webrtc 源码阅读 make_ref_counted模板函数用法

目录 1. 模板参数解析 1.1 typename T 1.2 typename... Args 1.3 typename std::enable_if::value, T>::type* nullptr 2. scoped_refptr 3. new RefCountedObject(std::forward(args)...); 4. 综合说明 5.在webrtc中的用法 5.1 peerConnectionFactory对象的构建过…

【MySQL】数据操作

数据操作 一、INSERT1、介绍2、语法3、语法介绍4、注意事项5、示例 二、插入否则更新1、介绍2、语法3、语法介绍4、示例 三、ROW_COUNT1、介绍2、示例 四、REPLACE1、介绍2、语法3、示例 五、UPDATE1、介绍2、语法3、示例 六、DELETE1、介绍2、语法3、语法介绍 七、TRUNCATE1、…