【C++】匿名对象 ③ ( 函数返回值为对象值时 匿名对象 的 拷贝构造函数 与 析构函数 调用情况分析 )

文章目录

  • 一、匿名函数 与 拷贝构造函数
  • 二、当函数返回值为对象时的情况分析





一、匿名函数 与 拷贝构造函数




1、匿名函数回顾


在上一篇博客 【C++】匿名对象 ② ( 将 “ 匿名对象 “ 初始化给变量 | 将 “ 匿名对象 “ 赋值给变量 ) 中 , 分析了匿名函数的几种用法 , 以及不同的使用场景下 , 匿名对象 的 创建与销毁情况 ;


C++ 编译器 发现 使用 匿名对象 时 , 会根据 匿名对象 的用法 , 决定对 匿名对象的 处理 ;


2、拷贝构造函数回顾


  • 【C++】拷贝构造函数调用时机 ① ( 使用一个对象初始化另外一个对象 | 将一个对象赋值给另外一个对象 )
  • 【C++】拷贝构造函数调用时机 ② ( 对象值作为函数参数 | 对象值作为函数返回值 )

博客中 , 分析了 拷贝构造函数 的调用时机 ;


" 拷贝构造函数 " 又称为 " 赋值构造函数 " , 该类型构造函数有 4 种调用时机 ;

  • ① 使用一个对象初始化另外一个对象 : 使用 一个 类实例对象 初始化 另外一个 类实例对象 ;
	// 使用一个对象初始化另外一个对象
	// 直接手动 调用拷贝构造函数
	Student s2 = Student(s1);
  • ② 将一个对象赋值给另外一个对象 : 将 一个 类实例对象 赋值给 另外一个 类实例对象 ;
	// 将一个对象赋值给另外一个对象
	// 自动调用拷贝构造函数
	Student s2 = s1;
  • ③ 对象值作为函数参数 : 类的实例对象 以值的方式 传递给函数 , 不是以 指针 或 引用 的方式 ;
// 定义函数, 接收 Student 对象值作为参数
void fun(Student s)
{
}
  • ④ 对象值作为函数返回值 : 函数直接返回类的实例对象 值 , 不是返回 指针 或 引用 ;
// 定义函数, 返回 Student 对象值作为返回值
Student fun()
{
	Student s1(18, 170);
	return s1;
}




二、当函数返回值为对象时的情况分析




1、函数返回对象值时返回值为匿名对象


如果一个 函数的返回值 是 类对象值 类型 , 不是 类对象的 引用 或 指针 类型 时 ,

返回的 返回值 是一个 匿名对象 ;

// 函数返回值是 Student 类型的对象
Student fun()
{
	Student s(12, 190);
	return s;
}

上述函数中执行的操作分析 :

  • 首先 , 调用 Student 类的 2 参数构造函数 , 创建 Student 类普通对象 , 初始化变量 s ;
  • 然后 , 返回 匿名对象 , 此时 调用 拷贝构造函数 , 将 普通对象 的值 拷贝给 匿名对象 ;
  • 再后 , 函数执行完毕 , 普通对象 需要被 销毁 , 此时调用析构函数 , 销毁 普通对象 ;

2、处理 函数返回的匿名对象


函数返回的匿名对象 有两种方案 :

  • 为 刚定义 变量 初始化 : 此时直接 将 匿名对象 转为 普通对象 ;
  • 为 已存在 变量 赋值 : 此时 将 匿名对象中的值取出 , 赋值给现有变量对象 , 匿名对象销毁 ;

3、代码示例 - 函数返回的匿名对象 初始化 变量


在下面的代码中 , fun 函数返回值是 Student 类型的匿名对象 ;

// 函数返回值是 Student 类型的对象
Student fun()
{
	Student s(12, 190);
	return s;
}

在 main 函数中 , 调用该 fun 函数 , 将 返回的 匿名对象 用于初始化 变量 s ;

	// 使用 函数返回匿名对象 初始化变量
	Student s = fun();

执行结果如下 :

调用带参数构造函数 m_age = 12
调用拷贝构造函数
调用析构函数 : m_age = 12
学生信息 : 年龄 = 12 , 身高 = 190
Press any key to continue . . .

逐条分析 构造函数 / 拷贝构造函数 / 析构函数 的调用过程 :

  • 调用带参数构造函数 m_age = 12 这是在 fun 函数中 , 调用 有参构造函数 , 创建 普通对象 ;
  • 调用拷贝构造函数 这是在 fun 函数中 , 函数返回对象值时 , 创建 要返回的 普通对象副本 , 也就是一个 匿名对象 ;
  • 调用析构函数 : m_age = 12 这是 fun 函数执行完毕 , 在函数作用域中的 普通对象 需要被析构销毁 ;
  • 学生信息 : 年龄 = 12 , 身高 = 190 在 main 函数中 , 由于 将 匿名函数 直接用于初始化 变量 s , 因此直接将 匿名对象 转为 普通对象 , 这是调用普通对象的方法打印的日志 ;

代码示例 :

#include "iostream"
using namespace std;

class Student
{
public:

	// 带参构造函数
	Student(int age, int height)
	{
		m_age = age;
		m_height = height;
		cout << "调用带参数构造函数 m_age = " << m_age << endl;
	}

	// 打印学生信息
	void printfInfo()
	{
		cout << "学生信息 : 年龄 = " << m_age  << " , 身高 = " << m_height << endl;
	}

	Student(const Student& s)
	{
		m_age = s.m_age;
		m_height = s.m_height;
		cout << "调用拷贝构造函数" << endl;
	}

	~Student()
	{
		cout << "调用析构函数 : m_age = " << m_age << endl;
	}

public:
	int m_age;		// 年龄
	int m_height;	// 身高
};

// 函数返回值是 Student 类型的对象
Student fun()
{
	Student s(12, 190);
	return s;
}


int main()
{
	// 使用 函数返回匿名对象 初始化变量
	Student s = fun();


	// 创建普通对象
	//Student s(18, 180);
		
	// 函数返回匿名对象直接赋值给已存在的对象
	//s = fun();


	// 调用对象方法
	s.printfInfo();


	// 控制台暂停 , 按任意键继续向后执行
	system("pause");
	return 0;
}

执行结果 :

调用带参数构造函数 m_age = 12
调用拷贝构造函数
调用析构函数 : m_age = 12
学生信息 : 年龄 = 12 , 身高 = 190
Press any key to continue . . .

在这里插入图片描述


4、代码示例 - 函数返回的匿名对象 为 变量 赋值


在下面的代码中 , fun 函数返回值是 Student 类型的匿名对象 ;

// 函数返回值是 Student 类型的对象
Student fun()
{
	Student s(12, 190);
	return s;
}

在 main 函数中 , 调用该 fun 函数 , 将 返回的 匿名对象 用于 赋值给已存在的 变量 s ;

	// 创建普通对象
	Student s(18, 180);
		
	// 函数返回匿名对象直接赋值给已存在的对象
	s = fun();

执行结果如下 :

调用带参数构造函数 m_age = 18
调用带参数构造函数 m_age = 12
调用拷贝构造函数
调用析构函数 : m_age = 12
调用析构函数 : m_age = 12
学生信息 : 年龄 = 12 , 身高 = 190
Press any key to continue . . .

逐条分析 构造函数 / 拷贝构造函数 / 析构函数 的调用过程 :

  • 调用带参数构造函数 m_age = 18 这是在 main 函数中 , 调用 有参构造函数 , 创建 普通对象 ;
  • 调用带参数构造函数 m_age = 12 这是在 fun 函数中 , 调用 有参构造函数 , 创建 普通对象 ;
  • 调用拷贝构造函数 这是在 fun 函数中 , 函数返回对象值时 , 创建 要返回的 普通对象副本 , 也就是一个 匿名对象 ;
  • 调用析构函数 : m_age = 12 这是 fun 函数执行完毕 , 在函数作用域中的 普通对象 需要被析构销毁 ;
  • 调用析构函数 : m_age = 12 这是在 main 函数中 , 使用 匿名对象 为 普通变量赋值 , 需要将 匿名对象的值赋值给普通对象 , 匿名对象 之后直接销毁 , 这是调用析构函数 销毁 fun 函数返回的匿名对象 ;
  • 学生信息 : 年龄 = 12 , 身高 = 190 在 main 函数中 , 执行 被 匿名对象 赋值的 普通变量对象 的成员函数 ;

代码示例 :

#include "iostream"
using namespace std;

class Student
{
public:

	// 带参构造函数
	Student(int age, int height)
	{
		m_age = age;
		m_height = height;
		cout << "调用带参数构造函数 m_age = " << m_age << endl;
	}

	// 打印学生信息
	void printfInfo()
	{
		cout << "学生信息 : 年龄 = " << m_age  << " , 身高 = " << m_height << endl;
	}

	Student(const Student& s)
	{
		m_age = s.m_age;
		m_height = s.m_height;
		cout << "调用拷贝构造函数" << endl;
	}

	~Student()
	{
		cout << "调用析构函数 : m_age = " << m_age << endl;
	}

public:
	int m_age;		// 年龄
	int m_height;	// 身高
};

// 函数返回值是 Student 类型的对象
Student fun()
{
	Student s(12, 190);
	return s;
}


int main()
{
	// 使用 函数返回匿名对象 初始化变量
	//Student s = fun();


	// 创建普通对象
	Student s(18, 180);
		
	// 函数返回匿名对象直接赋值给已存在的对象
	s = fun();


	// 调用对象方法
	s.printfInfo();


	// 控制台暂停 , 按任意键继续向后执行
	system("pause");
	return 0;
}

执行结果 :

调用带参数构造函数 m_age = 18
调用带参数构造函数 m_age = 12
调用拷贝构造函数
调用析构函数 : m_age = 12
调用析构函数 : m_age = 12
学生信息 : 年龄 = 12 , 身高 = 190
Press any key to continue . . .

在这里插入图片描述


http://www.niftyadmin.cn/n/5027674.html

相关文章

基于ntchat的微信群聊同步机器人

微信群有500人上限的限制&#xff0c;建立多个群的话又有信息无法互通的不便&#xff0c;此机器人通过自动将消息转发到同一个同步组内的所有群&#xff0c;消除这一不便性&#xff0c;间接达成扩大群成员数的目的。 效果演示&#xff1a; 项目地址&#xff1a; https://gith…

自动化测试框架实战详解

前言 之前文章跟大家分享了一下自己在接口自动化测试中进行测试准备的一些相关知识点&#xff0c;接下来本篇文章详细分享一下接口自动化框架设计的思路总结&#xff0c;希望能对初次探索接口自动化测试的小伙伴们有一些思路上的帮助。 小编是以pythonrequestsunittestHTMLTes…

centos如何安装最新版nodejs

在CentOS上安装最新版本的Node.js有两种主要的方法&#xff1a; 方法一&#xff1a;使用nvm&#xff08;Node Version Manager&#xff09; 在终端中输入以下命令以安装nvm&#xff1a; curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.38.0/install.sh | bash这…

API接口文档管理系统平台搭建(更新,附系统源码及教程)

简介 这是一款简洁大方的API接口文档管理系统&#xff0c;附系统源码及教程方法。可以轻松管理和使用API接口。 安装步骤 打开config/database.php配置数据库信息导入数据库data.sql设置运行目录为/public伪静态设置think PHP后台地址/admin/login.html 账号&#xff1a;adm…

GCC编译器CFLAGS、LDFLAGS详解

目录 前言一、CFLAGS、LDFLAGS详解1. CFLAGS2. LDFLAGS 二、常用的选项1、常用的编译选项2、常用的链接选项 三、使用注意事项 前言 在Linux开发中&#xff0c;我们经常用到Makefile来管理代码&#xff0c;进行代码的编译。一般的Makefile中都会包含CFLAGS、LDFLAGS两个选项&am…

豪越智慧后勤管理平台为企业带来哪些转变?

信息技术的迭代更新&#xff0c;为各行各业的发展插上了腾飞的翅膀。同时&#xff0c;不管是后勤管理部门&#xff0c;还是服务保障部门&#xff0c;如何在科技化浪潮、人工智能的时代背景下&#xff0c;更为高效和人性化地提供后勤管理和保障服务&#xff0c;是后勤部门不断精…

vscode 当中vue 全局自定义组件没有提示以及一些技巧

阅读技术文章可以查漏补缺&#xff0c;借鉴别人编码方式提高代码水平 阅读优秀项目 可以扩展业务处理能力 坚持每天阅读&#xff0c;每天学习新东西 积少成多&#xff0c;水到渠成 在写项目时候&#xff0c;我全局注册了组件&#xff0c;YhSwitch&#xff0c;但是在使用时候&am…

做外贸如何能够不被山寨呢

有的客户关心价格&#xff0c;有的客户关心质量&#xff0c;也有的客户担心被仿牌&#xff0c;当你的客户问你如何去防牌的时候&#xff1f;你该怎么回答呢&#xff1f; 来看看各位牛人的解答&#xff1a; 牛人一&#xff1a;这个控制其实最主要的还是在品牌方这边 品牌方一般…