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





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




1、匿名函数回顾


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


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

  • 匿名对象单独使用 : 如果只是单纯的使用 匿名对象 , 没有涉及到 将 匿名对象 赋值给其它变量 , 就会在表达式执行完毕后 , 销毁匿名对象 ;
  • 使用匿名对象初始化变量 : 如果 创建 匿名对象 后 , 还使用 匿名对象 初始化 变量 , 此时 编译器 会将 匿名对象 转为 普通对象 , 不会销毁该匿名对象 , 该对象会一直持续到该作用域结束 ;
  • 使用匿名对象为变量赋值 : 如果 创建 匿名对象 后 , 还使用 匿名对象 为 已存在的变量 赋值 , 此时 编译器 会将 匿名对象 的值赋值给 已存在的变量 , 并且立刻销毁该匿名对象 ;

2、拷贝构造函数回顾


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


" 拷贝构造函数 " 又称为 " 赋值构造函数 " , 该类型构造函数有 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 . . .

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/han1202012/article/details/132902770