二、类与对象(四)

22 内部类

22.1 内部类的概念

如果一个类定义在另一个类的内部,这个类就叫做内部类。内部类是一个独立的类,它不属于外部类,更不能通过外部类的对象去访问内部类的成员,外部类对内部类没有任何优越的访问权限,也就是说它和定义在一个全局的类没有什么区别,只是受外部类的类域限制。

例:

#include <iostream>
using namespace std;
class A
{
private:int h;
public:class B{private:int b;};
};
int main()
{//B bb; //错误代码A::B bb;//B受A的类域限制return 0;
}

22.2 内部类的特性

  1. 内部类天生就是外部类的友元,即内部类可以通过外部类的对象参数来访问外部类中的所有成员。但是外部类不是内部类的友元。

例:

#include <iostream>
using namespace std;
class A
{
private:static int k;int h;
public:class B // B天生就是A的友元{public:void foo(const A& a){//B可以访问A的私有成员cout << k << endl;//OKcout << a.h << endl;//OK}};
};
int A::k = 1;
int main()
{A::B b;b.foo(A());return 0;
}

运行结果:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  1. 内部类可以定义在外部类的publicprotected、和private也就是任何位置。

  2. sizeof(外部类)= 外部类,和内部类没有任何关系。

例:

#include <iostream>
using namespace std;
class A
{
private:int h;
public:class B{private:int b;};
};
int main()
{A aa;cout << sizeof(aa) << endl;return 0;
}

运行结果:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

23 匿名对象

23.1 匿名对象的引入及特性

以往我们调用成员函数的时候,通常的做法是会先定义一个对象,然后再通过这个对象去调用函数,但是有些时候比如我们在做题目,某个函数只需要被调用一次就可以了,如果定义一个对象才能调用就有些麻烦了,这个时候我们就可以通过匿名对象来对函数进行调用。

以往我们说不能用A aa1();这样的方式来定义对象,因为编译器无法识别这是一个函数声明,还是对象定义。

定义匿名对象的方式和上面的方式类似,但是它不用取名字,而且匿名对象的生命周期只在它出现的那一行

例:

#include <iostream>
using namespace std;
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();cout << "-----" << endl;cout << Solution().Sum_Solution(10) << endl;return 0;
}

运行结果:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

从输出结果可以看到,27行的时候定义了一个匿名对象,到了28行后它就自动调用了析构函数。

除此之外,29行还展示了匿名对象的应用场景,即对于那些需要通过对象来调用函数但对象本身并不重要的情况,就可以通过匿名对象进行调用。当然还有一些其他使用场景,这个等以后遇到再说。

23 编译器对拷贝对象时的一些优化

在传参和传返回值的过程中,为减少对象的拷贝,通常编译器会对以下场景做一些优化:

23.1 连续构造和拷贝构造时的优化

#include <iostream>
using namespace std;
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;
};int main()
{A aa1 = 1;//构造+拷贝构造return 0;
}

运行结果:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

从输出结果可以看到,35行代码本来应该涉及一个构造和一个拷贝构造,但被编译器优化后只涉及一个构造。

23.2 参数类型为引用时的优化

#include <iostream>
using namespace std;
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 Fun2(const A& aa)
{}
int main()
{A aa1 = 1;cout << "-----" << endl;Fun2(aa1);//aa只是aa1的别名,无优化cout << "-----" << endl;Fun2(2);//构造一个临时变量后给别名,无优化cout << "-----" << endl;Fun2(A(3));//return 0;
}

运行结果:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

从输出结果可以看到, 当函数参数类型为引用时,因为形参只是实参的一个别名,所以不需要做任何优化。

结论:尽量使用const &传参。

23.3 传值返回时的优化

#include <iostream>
using namespace std;
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 Fun1(A aa)
{}
void Fun2(const A& aa)
{}
A Fun3()
{A aa;//构造return aa;//拷贝构造
}
A Fun4()
{return A();
}
int main()
{A aa1 = 1;cout << "-----" << endl;Fun3();//无优化cout << "-----" << endl;A aa2 = Fun3();//本来应该是一个构造,两个拷贝构造,但被编译器优化为一个构造和一个拷贝构造cout << "-----" << endl;Fun4();//构造+拷贝构造->优化为直接构造A aa3 = Fun4();//构造+拷贝构造+拷贝构造->优化为直接构造cout << "-----" << endl;return 0;
}

运行结果:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

从输出结果可以看到,51行代码本来应该涉及一个构造和两个拷贝构造,但被编译器优化为和49行代码一样,只涉及一个构造和一个拷贝构造。除此之外,58行代码直接返回一个匿名对象时,本来应该涉及一个构造和两个拷贝构造,但被编译器优化后,只涉及一个构造。

需要注意的是,下面这种情况无法优化:

A aa1;
aa1 = Fun4();

原因在于,和A aa3 = Fun4();相比,aa1 = Fun4();还涉及到赋值运算符的重载,这将干扰优化的进行。

结论:

  1. 接收返回值对象,尽量以拷贝构造的方式接收,不要赋值接收。
  2. 函数中返回对象时,尽量返回匿名对象。

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

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

相关文章

LINUX基础培训之开机启动过程

前言、本章学习目标 掌握系统启动、引导过程 了解grub.conf的参数设置 熟悉系统运行级别 了解加载内核过程 一、LINUX启动引导过程 Linux系统的启动过程并不是大家想象中的那么复杂&#xff0c;其过程可以分为5个阶段&#xff1a; 1.开机自检 服务器主机开机以后&#xf…

Spring Beans的魔法门:解密多种配置方式【beans 四】

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 Spring Beans的魔法门&#xff1a;解密多种配置方式【beans 四】 前言XML配置方式1. 声明和配置Bean&#xff1a;2. 构造函数注入&#xff1a;3. 导入其他配置文件&#xff1a; java注解方式1. 使用Co…

算法训练营Day35

#Java #动态规划 开源学习资料 Feeling and experiences&#xff1a; 不同路径&#xff1a;力扣题目链接 一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为 “Start” &#xff09;。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右…

MyBatisPlus学习三:Service接口、代码生成器

学习教程 黑马程序员最新MybatisPlus全套视频教程&#xff0c;4小时快速精通mybatis-plus框架 Service接口 简介 在MyBatis-Plus框架中&#xff0c;Service接口的作用是为实体类提供一系列的通用CRUD&#xff08;增删改查&#xff09;操作方法。通常情况下&#xff0c;Servi…

PyTorch 入门学习数据操作之创建

简介 在深度学习中&#xff0c;我们通常会频繁地对数据进行操作&#xff1b;要操作一般就需要先创建。 官方介绍 The torch package contains data structures for multi-dimensional tensors and defines mathematical operations over these tensors. Additionally, it pr…

SpringMVC通用后台管理系统源码

整体的SSM后台管理框架功能已经初具雏形&#xff0c;前端界面风格采用了结构简单、 性能优良、页面美观大的Layui页面展示框架 数据库支持了SQLserver,只需修改配置文件即可实现数据库之间的转换。 系统工具中加入了定时任务管理和cron生成器&#xff0c;轻松实现系统调度问…

【源码解析】Apache RocketMQ发送消息源码

send message源码解析 引入 send message方法作为我们经常使用的方法&#xff0c;平时我们很难去关注他底层到底做了什么。大部分人只知道通过send message方法可以将消息发送到broker&#xff0c;然后供消费者进行消费。其实不然&#xff0c;消息从客户端发送到broker&#x…

ssm基于vue.js的购物商场的设计与实现论文

摘 要 传统办法管理信息首先需要花费的时间比较多&#xff0c;其次数据出错率比较高&#xff0c;而且对错误的数据进行更改也比较困难&#xff0c;最后&#xff0c;检索数据费事费力。因此&#xff0c;在计算机上安装购物商场软件来发挥其高效地信息处理的作用&#xff0c;可以…

cissp 第10章 : 物理安全要求

10.1 站点与设施设计的安全原则 物理控制是安全防护的第一条防线&#xff0c;而人员是最后一道防线。 10.1.1 安全设施计划 安全设施计划通过关键路径分析完成。 关键路径分析用于找出关键应用、流程、运营以及所有必要支撑元索间的关系。 技术融合指的是各种技术、解决方案…

性能优化-OpenMP基础教程(三)

本文主要介绍OpenMP并行编程的环境变量和实战、主要对比理解嵌套并行的效果。 &#x1f3ac;个人简介&#xff1a;一个全栈工程师的升级之路&#xff01; &#x1f4cb;个人专栏&#xff1a;高性能&#xff08;HPC&#xff09;开发基础教程 &#x1f380;CSDN主页 发狂的小花 &…

书生·浦语大模型全链路开源体系 学习笔记 第一课

背景 大模型是发展人工通用人工智能的一个重要途径&#xff0c;能够解决多种任务和多种模态&#xff0c;展示了一个更面向更高阶的智能的潜在途径。大模型的发展历程是从专用模型到通用模型的过程&#xff0c;从语音识别、图像识别、人脸识别等专用模型&#xff0c;到通用的大…

Java8内置四大核心函数式接口

先来看几个例子,主要练习策略模式: 用策略模式的做法 定义个接口 其实像这样的接口并不需要我们自己创建 java8推出的Lambda表达式主要就是为了简化开发,而Lambda表达式 的应用主要是针对与函数式接口,自然也推出了对应的一些接口 /*** Java8 内置的四大核心函数式接口** C…

【C++】STL 算法 ③ ( 函数对象中存储状态 | 函数对象作为参数传递时值传递问题 | for_each 算法的 函数对象 参数是值传递 )

文章目录 一、函数对象中存储状态1、函数对象中存储状态简介2、示例分析 二、函数对象作为参数传递时值传递问题1、for_each 算法的 函数对象 参数是值传递2、代码示例 - for_each 函数的 函数对象 参数在外部不保留状态3、代码示例 - for_each 函数的 函数对象 返回值 一、函数…

权威认可!甄知科技猪齿鱼产品荣获信创产品评估证书

近日&#xff0c;依据《信息技术应用创新产品评估规范 第1部分&#xff1a;应用软件》&#xff08;T/SSIA 2001-2022&#xff09;&#xff0c;经过严格评估&#xff0c;甄知科技旗下自主研发的猪齿鱼数智化开发管理平台 V2.0.0&#xff0c;通过信创测试认证&#xff0c;获得上海…

差分约束算法

差分约束 差分约束系统包含 m m m个涉及 n n n个变量的差额限制条件&#xff0c;这些差额限制条件每个都是形式为 x i − x j ≤ b ∈ [ 1 , m ] x_i-x_j\leq b_{\in[1,m]} xi​−xj​≤b∈[1,m]​的简单线性不等式。 通常我们要求解出一组可行解。 最短路差分约束 如果我们…

ubuntu 22 virt-manger(kvm)安装winxp; ubuntu22体验 firebird3.0

安装 、启动 virt-manager sudo apt install virt-manager sudo systemctl start libvirtdsudo virt-manager安装windowsXP 安装过程截图如下 要点1 启用 “包括寿终正寝的操作系统” win_xp.iso 安装过程 &#xff1a; 从winXp.iso启动, 执行完自己重启从硬盘重启&#xff0c…

稿件代写3个不可或缺的步骤让你事半功倍-华媒舍

作为一个需求频繁的作者&#xff0c;你可能会面临大量的稿件代写任务。但是&#xff0c;你是否曾经为提高文章质量而苦恼过&#xff1f;是否希望在有限的时间内完成更多的代写任务&#xff1f;本篇文章将向你介绍三个不可或缺的稿件代写步骤&#xff0c;帮助你事半功倍&#xf…

Redis高级特性和应用(慢查询、Pipeline、事务、Lua)

Redis的慢查询 许多存储系统(例如 MySQL)提供慢查询日志帮助开发和运维人员定位系统存在的慢操作。所谓慢查询日志就是系统在命令执行前后计算每条命令的执行时间,当超过预设阀值,就将这条命令的相关信息(例如:发生时间,耗时,命令的详细信息)记录下来,Redis也提供了类似…

Huggy Lingo: 利用机器学习改进 Hugging Face Hub 上的语言元数据

太长不看版: Hub 上有不少数据集没有语言元数据&#xff0c;我们用机器学习来检测其语言&#xff0c;并使用 librarian-bots 自动向这些数据集提 PR 以添加其语言元数据。 Hugging Face Hub 已成为社区共享机器学习模型、数据集以及应用的存储库。随着 Hub 上的数据集越来越多&…

[概率论]四小时不挂猴博士

贝叶斯公式是什么 贝叶斯公式是概率论中的一个重要定理&#xff0c;用于计算在已知一些先验信息的情况下&#xff0c;更新对事件发生概率的估计。贝叶斯公式的表达式如下&#xff1a; P(A|B) P(B|A) * P(A) / P(B) 其中&#xff0c;P(A|B)表示在事件B发生的条件下事件A发生的概…