当前位置: 首页 > article >正文

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对象a
	cout << "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}; // 创建有名对象vect1
	print_vector(vect1);
	vector<int> vect2 = vector<int>{ 4, 5, 6 }; // 创建匿名对象vect2
	print_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); // 创建有名对象per1
	Person per2(per1); // 拷贝构造创建有名对象per2
	per2.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.kler.cn/news/309426.html

相关文章:

  • linux网络命令:使用最多最广泛的网络抓包工具tcpdump详细介绍
  • MATLAB入门教程
  • 检查一个复数C的实部a和虚部b是否都是有限数值即a和b都不是无限数值、空值cmath.isfinite(x)
  • MES管理系统在智能制造中的重要应用
  • CMU 10423 Generative AI:lec5(Encoder-only Transformers + 阅读材料Bert, ViT)
  • 如何理解BCEWithLogitsLoss()
  • 什么是期权日内交易?怎么做日内期权策略?
  • MyBatis 源码解析:Mapper 文件加载与解析
  • 导弹追踪问题:蒙特卡罗模拟+matlab代码
  • Linux7-su,exit,sudo
  • Java 中的 sleep、wait、join 怎么理解
  • linux中的kill、pkill和killall
  • C++速通LeetCode简单第3题-相交链表
  • RTMP协议在无人机巡检中的应用场景
  • 【深度学习】【OnnxRuntime】【Python】模型转化、环境搭建以及模型部署的详细教程
  • Java学习线路(2024版)
  • 简单了解微服务--黑马(在更)
  • 安全运维教程(非常详细)从零基础入门到精通,看完这一篇就够了
  • 【Pycharm使用技巧记录手册】批量检索与替换功能——辅助Yolo训练标签label配置文件构建
  • Mac笔记本上查看/user/目录下的文件的几种方法
  • mysql配置优化和分组报错问题解决
  • 信号与线性系统综合实验
  • 87-java 可轮询锁和定时锁
  • 网络安全宣传周的时间,举办活动的方式和意义
  • 计算机毕业设计公交站点线路查询网站登录注册搜索站点线路车次/springboot/javaWEB/J2EE/MYSQL数据库/vue前后分离小程序
  • 场外个股期权通道商是什么业务?个人投资者可以参与场外期权吗?
  • JavaScript ES6特性(var let const、function=>、增强表达赋值、类与对象)
  • 【大模型专栏—进阶篇】语言模型创新大总结——“三派纷争”
  • 微信小程序点赞动画特效实现
  • [乱码]确保命令行窗口与主流集成开发环境(IDE)统一采用UTF-8编码,以规避乱码问题