在上一篇博客 【C++】匿名对象 ② ( 将 “ 匿名对象 “ 初始化给变量 | 将 “ 匿名对象 “ 赋值给变量 ) 中 , 分析了匿名函数的几种用法 , 以及不同的使用场景下 , 匿名对象 的 创建与销毁情况 ;
C++ 编译器 发现 使用 匿名对象 时 , 会根据 匿名对象 的用法 , 决定对 匿名对象的 处理 ;
在
博客中 , 分析了 拷贝构造函数 的调用时机 ;
" 拷贝构造函数 " 又称为 " 赋值构造函数 " , 该类型构造函数有 4 种调用时机 ;
// 使用一个对象初始化另外一个对象
// 直接手动 调用拷贝构造函数
Student s2 = Student(s1);
// 将一个对象赋值给另外一个对象
// 自动调用拷贝构造函数
Student s2 = s1;
// 定义函数, 接收 Student 对象值作为参数
void fun(Student s)
{
}
// 定义函数, 返回 Student 对象值作为返回值
Student fun()
{
Student s1(18, 170);
return s1;
}
如果一个 函数的返回值 是 类对象值 类型 , 不是 类对象的 引用 或 指针 类型 时 ,
返回的 返回值 是一个 匿名对象 ;
// 函数返回值是 Student 类型的对象
Student fun()
{
Student s(12, 190);
return s;
}
上述函数中执行的操作分析 :
函数返回的匿名对象 有两种方案 :
在下面的代码中 , 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 . . .
在下面的代码中 , 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 . . .