C++系列-匿名对象

匿名对象

  • 💢什么是匿名对象
  • 💢匿名对象的创建方式及作用域
  • 💢匿名对象的对象类型
    • 💢💢匿名的基本数据类型对象
    • 💢💢匿名的自定义的类类型对象
    • 💢💢匿名的标准库的类对象
  • 💢匿名对象的使用方式
    • 💢💢作为临时值使用
    • 💢💢可以调用成员
    • 💢💢赋值和初始化
  • 💢匿名对象的注意事项
    • 💢💢权限问题
    • 💢💢不能取地址
    • 💢💢缺陷

💢什么是匿名对象

  • 🥝匿名对象(Anonymous Object) 是指在创建对象的时候,并没有给它命名。
  • 🥝它们通常用于在单个语句中执行一系列操作或调用某个函数,并且不需要将其结果存储到对象中

💢匿名对象的创建方式及作用域

  • 🍍直接在类名后加(),当遇到有参或者拷贝构造时,需要加上相应的参数
  • 🍍有名对象,其生命周期在当前函数局部域。
  • 🍍匿名对象,其生命周期在当前行。
code:
#include <iostream>
using namespace std;class Person
{
public:Person(){cout << "Person默认构造" << endl;}Person(string name){cout << "Person有参构造" << endl;m_name = name;}Person(const Person& per){cout << "Person拷贝构造" << endl;}~Person(){cout << "析构析构析构" << endl;}void print_info(){cout << "name: " << m_name << endl;}private:string m_name="huahua";
};int main()
{Person per1;		// 有名对象 -- 生命周期在当前函数局部域per1.print_info();Person().print_info();			// Person(),匿名对象 -- 生命周期在当前行Person("lili").print_info();	// Person("lili"),匿名对象 -- 生命周期在当前行Person(per1).print_info();		// Person(per1),匿名对象 -- 生命周期在当前行system("pause");return 0;
}result:
Person默认构造
name: huahua
Person默认构造
name: huahua
析构析构析构
Person有参构造
name: lili
析构析构析构
Person拷贝构造
name: huahua
析构析构析构

👉👉👉
这段代码中,Person().print_info(),Person(“lili”).print_info(),Person(per1).print_info()均是匿名对象。
他们只是实例化对象时,运行的构造函数不一样。 可以看到,当实例化匿名对象的那一行代码执行完之后,就执行了析构函数,释放对象。
而有名对象是在main函数的作用域,等main函数执行完后,才会执行析构函数(本案例中看不到,
因为最后可看到的的执行结果停留在system(“pause”))这一步。

💢匿名对象的对象类型

  • 🍇匿名对象的类型可以是基本数据类型,如int,double, char等。
  • 🍇匿名对象的类型可以是自定义的类类型
  • 🍇匿名对象的类型可以是标准库中的类类型

💢💢匿名的基本数据类型对象

👉👉👉
int(5), double(3.14) char(‘A’)就是在创建匿名对象。
下面代码中的int(),int(3)是在创建匿名的int类型对象。 int a =
int(10)创建匿名对象int(10),并将其赋值给a,a就是有名对象。

code:
#include <iostream>
using namespace std;void test01()
{cout << "int(): " << int() << endl;		// 创建匿名的int类型对象cout << "int(3): " << int(3) << endl;int a = int(10);			// 创建匿名int类型对象int(10),赋值给有名的int对象acout << "int a = int(10): " << a << endl;
}
int main()
{test01();system("pause");return 0;
}result:
int(): 0
int(3): 3
int a = int(10): 10

💢💢匿名的自定义的类类型对象

👉👉👉
之前代码示例中的如下语句均为创建匿名对象。 Person().print_info(); // Person(),匿名对象
– 生命周期在当前行 Person(“lili”).print_info(); // Person(“lili”),匿名对象 – 生命周期在当前行 Person(per1).print_info(); // Person(per1),匿名对象 – 生命周期在当前行
而如下代码是在创建有名对象per1。 Person per1; // 有名对象 – 生命周期在当前函数局部域

💢💢匿名的标准库的类对象

#include <iostream>
#include <vector>
using namespace std;void print_vector(const vector<int>& vec)
{for (vector<int>::const_iterator it = vec.begin(); it < vec.end(); it++){cout << *it << " ";}cout << endl;
}void test01()
{print_vector(vector<int>{0, -1, -2}); // 创建匿名对象 vector<int>{0, -1, -2}vector<int> vect1{1, 2, 3}; // 创建有名对象vect1print_vector(vect1);vector<int> vect2 = vector<int>{ 4, 5, 6 }; // 创建匿名对象vect2print_vector(vect2);
}
int main()
{test01();system("pause");return 0;
}result:
0 -1 -2
1 2 3
4 5 6

💢匿名对象的使用方式

💢💢作为临时值使用

#include <iostream>
using namespace std;void print_info(int a)
{cout << a << endl;
}int main()
{print_info(3); // 这里的3可以看作是匿名的int对象,即int(3)system("pause");return 0;
}result:
3

💢💢可以调用成员

👉👉👉
之前代码示例中的如下语句中的匿名对象可以调用成员,但也只能调用一次,后面不会再用到它, 所以不需要有有名对象存储。
Person().print_info(); // Person(),匿名对象 – 生命周期在当前行
Person(“lili”).print_info(); // Person(“lili”),匿名对象 – 生命周期在当前行
Person(per1).print_info(); // Person(per1),匿名对象 – 生命周期在当前行

💢💢赋值和初始化

👉👉👉
下面代码中int a = Person(“Feifei”, 10).get_age(); 中,Person(“Feifei”,
10)是匿名对象,它调用了成员函数get_age(), 给变量a赋值。

Person per1 = Person(“Maomao”, 13); 中,Person(“Maomao”,
13)匿名对象配置给有名对象per1。

#include <iostream>
using namespace std;class Person
{
public:Person(string name, int age) : m_name(name), m_age(age) {}int get_age(){return m_age;}
private:string m_name = "huahua";int m_age = 10;
};int main()
{// Person("Feifei", 10)匿名对象调用其成员函数给其它变量赋值int a = Person("Feifei", 10).get_age(); cout << "a:" << a << endl;// 匿名对象Person("Maomao", 13),可以用于初始化per1对象,Person per1 = Person("Maomao", 13); system("pause");return 0;
}result:
a:10

💢匿名对象的注意事项

💢💢权限问题

👉👉👉
下面代码中int a = Person(“Feifei”, 10).get_age();
中,Person(“Feifei”, 10)是匿名对象,它调用了成员函数get_age(), 给变量a赋值。

Person per1 = Person(“Maomao”, 13); 中,Person(“Maomao”,
13)匿名对象配置给有名对象per1。

#include <iostream>
using namespace std;class Person
{
public:Person(string name, int age) : m_name(name), m_age(age) {}Person(Person& per) : m_name(per.m_name), m_age(per.m_age) {}int get_age(){return m_age;}void set_age(int age){m_age = age;}void print_info(){cout << "name: " << m_name << ", age: " << m_age << endl;}
private:string m_name = "huahua";int m_age = 10;
};int main()
{Person per1("Tiantian", 12); // 创建有名对象per1Person per2(per1); // 拷贝构造创建有名对象per2per2.print_info();system("pause");return 0;
}result:
name: Tiantian, age: 12

👉👉👉
以上代码中,先创建有名对象per1,然后利用per1创建有名对象per2。代码没有问题。 下面使用匿名函数实现。

#include <iostream>
using namespace std;class Person
{
public:Person(string name, int age) : m_name(name), m_age(age) {}Person(Person& per) : m_name(per.m_name), m_age(per.m_age) {}int get_age(){return m_age;}void set_age(int age){m_age = age;}void print_info(){cout << "name: " << m_name << ", age: " << m_age << endl;}
private:string m_name = "huahua";int m_age = 10;
};int main()
{// 想使用Person("Tiantian", 12)匿名对象去利用拷贝构造创建per2对象// 编译会报错,错误	C2558	class“Person” : 没有可用的复制构造函数或复制构造函数声明为“explicit”// 原因就在于这个匿名对象,它和临时对象一样是具有常性的,而在拷贝构造中,接收的是Person& per,// 用一个非常性的对象去引用常性的就会有问题。编译器会认为是权限放大的问题。Person per2(Person("Tiantian", 12)); per2.print_info();system("pause");return 0;
}

👉👉👉
以上代码中,想使用Person(“Tiantian”, 12)匿名对象去利用拷贝构造创建per2对象。
匿名对象,它和临时对象一样是具有常性的,而在拷贝构造中,接收的是Person& per,
用一个非常性的对象去引用常性的就会有问题。编译器会认为是权限放大的问题。会报错。 修改方法为:Person(Person& per) :
m_name(per.m_name), m_age(per.m_age) {} 在 Person& per前加上const修饰即可。

加上const后实现了权限平移,此时既可以接受普通引用也可以接收常引用,提高了代码的健壮性。

💢💢不能取地址

cout << &Person("Tiantian", 12) << endl;  会报错。
因为匿名对象随时可能被销毁,如果取了其地址,后续的代码会变得不稳定,而且编译器可能会对匿名对象进行优化,
如果将其存储于寄存器中,就娶不到确定的内存地址。

💢💢缺陷

调试和维护上的困难,无法使用debug模式直接跟踪和check其当前值,增加调试难度。
如果频繁的创建和销毁匿名对象,会影响性能的开销。

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

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

相关文章

CleanClip vs 传统剪贴板:究竟谁更胜一筹?

在日常工作和生活中,复制粘贴可以说是我们使用最频繁的操作之一。传统的剪贴板功能虽然简单易用,但在功能性和效率上还有很大的提升空间。今天,我们就来比较一下新兴的剪贴板增强工具CleanClip与传统剪贴板,看看到底谁更胜一筹。 1. 剪贴历史管理 传统剪贴板只能存储最后一次…

通过adb命令打开手机usb调试

adb shell settings put global adb_enabled 1 这个命令会将全局ADB启用设置为1&#xff0c;允许通过ADB进行调试。 adb shell settings put secure adb_authentication_enabled 1 这个命令会启用ADB身份验证&#xff0c;允许设备在连接时要求授权。 adb shell settings put …

【Java】类的成员之一-代码块【主线学习笔记】

文章目录 前言类的成员之一-代码块作用静态初始化块非静态代码块 前言 Java是一门功能强大且广泛应用的编程语言&#xff0c;具有跨平台性和高效的执行速度&#xff0c;广受开发者喜爱。在接下来的学习过程中&#xff0c;我将记录学习过程中的基础语法、框架和实践技巧等&#…

Pyspark下操作dataframe方法(3)

文章目录 Pyspark dataframe操作方式3df.foreach 逐条执行foreachPartition 按分区逐条执行freqltemsgroupBy 分组head 获取指定数量开头hint 查询优化intersect 获取交集&#xff08;去重&#xff09;isEmpty 判断dataframe是否为空join 关联limit 限定数量mapInPandas 迭代处…

PaddleNLP本文分类及docker部署流程

本文记录使用PaddleNLP进行文本分类的全流程 参考&#xff1a;https://github.com/PaddlePaddle/PaddleNLP/tree/develop/legacy/applications/text_classification/multi_class 文章目录 1. 数据准备2. 模型训练2.1 准备关键库2.2 模型训练&#xff06;验证2.3 模型测试2.4 结…

分布式中间件-redis相关概念介绍

文章目录 什么是redis?示意图Redis的主要特点Redis的主要用途Redis的工作原理Redis的持久化与备份 redis 6.x新增特性多线程数据加载客户端缓存新的 RESP 3 协议支持ACL&#xff08;Access Control List&#xff09;功能新增数据类型性能改进配置文件的改进其他改进 redis数据…

前端vue中如何给reactive赋值

const deviceDatareactive({}) const getDeviceDetail (list)>{ if(list.length > 0){ for(let item of list){ if(item.id param.id){ Object.assign(deviceData,item) } } } }

02 基于STM32的按键控制继电器驱动电机

本专栏所有源资料都免费获取&#xff0c;没有任何隐形消费。 注意事项&#xff1a;STM32仿真会存在各种各样BUG&#xff0c;且尽量按照同样仿真版本使用。本专栏所有的仿真都采用PROTEUS8.15。 本文已经配置好STM32F103C8T6系列&#xff0c;在PROTUES仿真里&#xff0c;32单片…

Doker学习笔记--黑马

介绍&#xff1a;快速构建、运行、管理应用的工具 在不同的服务器上部署多个应用&#xff0c;但是往往不同应用之间会有冲突&#xff0c;因为它们所依赖的环境&#xff0c;函数库&#xff0c;配置都不一样&#xff0c;此时docker在运行时形成了一个隔离环境&#xff08;容器&am…

【C++篇】C++类与对象深度解析(三):类的默认成员函数详解

文章目录 【C篇】C类与对象深度解析&#xff08;三&#xff09;前言4. 运算符重载基本概念4.1 运算符重载的基本概念4.2 重载运算符的规则4.3 成员函数重载运算符4.4 运算符重载的优先级与结合性4.5 运算符重载中的限制与特殊情况4.5.1 不能创建新的操作符4.5.2 无法重载的运算…

李宏毅机器学习2023-HW13-Network Compression

文章目录 TaskLinkBaselineSimple BaselineMedium BaselineStrong BaselineBoss BaselineFitNet Knowledge DistillationRelational Knowledge Distillation (RKD)Distance Metric (DM) Knowledge Distillation Task 通过network compression完成图片分类&#xff0c;数据集跟…

QT 带箭头的控件QPolygon

由于对当前项目需要绘制一个箭头控件&#xff0c;所以使用了QPainter和QPolygon来进行绘制&#xff0c;原理就是计算填充&#xff0c;下面贴出代码和效果图 这里简单介绍下QPolygon QPolygon是继承自 QVector<QPoint>那么可以很简单的理解为&#xff0c;他就是一个点的…

Leetcode面试经典150题-138.随机链表的复制

题目比较简单&#xff0c;重点是理解思想&#xff0c;random不管&#xff0c;copy一定要放在next 而且里面的遍历过程不能省略 解法都在代码里&#xff0c;不懂就留言或者私信 /* // Definition for a Node. class Node {int val;Node next;Node random;public Node(int val…

springboot-创建连接池

操作数据库 代码开发步骤&#xff1a; pom.xml文件配置依赖properties文件配置连接数据库信息&#xff08;连接池用的是HikariDataSource&#xff09;数据库连接池开发 configurationproperties和value注解从properties文件中取值bean方法开发 service层代码操作数据库 步骤&am…

数据分析师的得力助手:vividime Desktop让数据分析变得更简单高效

在数据驱动决策的今天&#xff0c;数据分析已成为企业不可或缺的一部分。面对海量的数据和复杂的业务需求&#xff0c;一款高效、易用的报表工具显得尤为重要。本文将深入解析为何一款优秀的报表工具对于数据分析至关重要&#xff0c;并以市场上备受好评的免费BI工具——vividi…

集成学习详细介绍

以下内容整理于&#xff1a; 斯图尔特.罗素, 人工智能.现代方法 第四版(张博雅等译)机器学习_温州大学_中国大学MOOC(慕课)XGBoost原理介绍------个人理解版_xgboost原理介绍 个人理解-CSDN博客 集成学习(ensemble)&#xff1a;选择一个由一系列假设h1, h2, …, hn构成的集合…

YOLOv10改进系列,YOLOv10损失函数更换为Powerful-IoU(2024年最新IOU),助力高效涨点

改进前训练结果: 改进后的结果: 摘要 边界框回归(BBR)是目标检测中的核心任务之一,BBR损失函数显著影响其性能。然而,观察到现有基于IoU的损失函数存在不合理的惩罚因子,导致回归过程中锚框扩展,并显著减缓收敛速度。为了解决这个问题,深入分析了锚框扩展的原因。针…

【网络】详解HTTP协议的CGI机制和CGI进程

目录 引言 CGI机制模型 伪代码示例 个人主页&#xff1a;东洛的克莱斯韦克-CSDN博客 引言 CGI机制是HTTP协议提供的偏底层的一套机制&#xff0c;也是非常重要的机制——它让大量的业务进程和HTPP协议解耦。而CGI进程是业务层的&#xff0c;用来处理各种数据&#xff0c;比…

OpenCV结构分析与形状描述符(24)检测两个旋转矩形之间是否相交的一个函数rotatedRectangleIntersection()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 测两个旋转矩形之间是否存在交集。 如果存在交集&#xff0c;则还返回交集区域的顶点。 下面是一些交集配置的例子。斜线图案表示交集区域&#…

孙怡带你深度学习(2)--PyTorch框架认识

文章目录 PyTorch框架认识1. Tensor张量定义与特性创建方式 2. 下载数据集下载测试展现下载内容 3. 创建DataLoader&#xff08;数据加载器&#xff09;4. 选择处理器5. 神经网络模型构建模型 6. 训练数据训练集数据测试集数据 7. 提高模型学习率 总结 PyTorch框架认识 PyTorc…