C++中的析构函数和拷贝构造函数
1. 构造函数
构造函数用于在对象创建时初始化对象的成员变量。C++支持无参构造函数和有参构造函数。
示例代码:
class Hero {
public:
Hero() {
m_Hp = 666;
cout << "无参构造函数构造完毕" << endl;
}
Hero(float hp) {
m_Hp = hp;
cout << "有参构造函数构造完毕" << endl;
}
private:
float m_Hp;
};
2. 拷贝构造函数
拷贝构造函数用于通过另一个同类型对象来初始化新创建的对象。其形式为ClassName(const ClassName &other)
。参数使用const和引用是为了提高效率和防止原对象被修改。
详细解释:
1、const,因为拷贝函数只是传递一个变量,但不改变原变量,所以用const
2、&是表明传进的是原始变量的别名,不是以形参的形式传进来,所以用&取地址符号
示例代码:
Hero(const Hero& h) {
m_Hp = h.m_Hp;
cout << "拷贝函数构造完毕" << endl;
}
拷贝构造函数的三种主要用途:
- 用一个已存在的对象初始化另一个对象。
- 函数传参时传递对象。
- 函数返回值为对象。
3. 析构函数
析构函数用于在对象销毁时执行清理工作。它的形式为~ClassName()
。析构函数在对象生命周期结束时自动调用。
示例代码:
~Hero() {
cout << "析构函数调用完毕" << endl;
}
代码示例和运行结果
#include<iostream>
using std::cout;
using std::endl;
class Hero{
public:
Hero(){
m_Hp = 666;
cout << "无参构造函数构造完毕" << endl;
}
Hero(float hp){
m_Hp = hp;
cout << "有参构造函数构造完毕" << endl;
}
Hero(const Hero& h){ // 在这里是定义一个拷贝函数
/*
详细解读函数参数的形式,const Hero& h
1、const,应为拷贝函数只是传递一个变量,但不改变原变量,所以用const
2、&是传进的是原始变量的别名,不是以形参的形式传进来,所以用&取地址符号
*/
m_Hp = h.m_Hp;
cout << "拷贝函数构造完毕" << endl;
}
//这个是析构函数,用于在调用完这个类实例化的对象后释放对应内存,编译器自动调用的一个函数
//命名规则是:~类名(){}
~Hero(){
cout << "析构函数调用完毕" << endl;
}
private:
float m_Hp;
};
// fun1 函数主要看类的拷贝函数的第一个功能:用一个已经实例化的对象初始化另一个对象。
void func1(){
cout << "----------func1----------" << endl;
Hero h1(20);
Hero h2 = Hero(h1);
}
void test1(Hero h){
}
void test2(Hero* h){
}
// fun2 函数主要看类的拷贝函数的第二个功能:传参
void func2(){
cout << "----------func2----------" << endl;
Hero h1;
test1(h1); // 传进来一个实例化的对象,执行拷贝函数
test2(&h1); // 传进来的是一个地址,并没有在内存上拷贝一个新的对象
}
Hero test3(){
cout << "----------func3----------" << endl;
Hero h(40);
return h;
}
// func3 函数主要是看类的拷贝函数的三个功能:返回值
void func3(){
Hero h = test3();//这里Hero类变量h接受test3()函数返回的一个用40作为m_Hp属性的变量,使用拷贝函数
//由于这里编译器给优化掉了,所以一般的集成编译环境展示不出来是否调用了拷贝函数,但是逻辑上是调用了的。
}
int main(){
func1();
func2();
func3();
return 0;
}
运行结果:
----------func1----------
有参构造函数构造完毕
拷贝函数构造完毕
析构函数调用完毕
析构函数调用完毕
----------func2----------
无参构造函数构造完毕
拷贝函数构造完毕
析构函数调用完毕
析构函数调用完毕
----------func3----------
有参构造函数构造完毕
拷贝函数构造完毕
析构函数调用完毕
析构函数调用完毕
##attention
(对于func3一般编译器最终运行的结果是
“有参构造函数构造完毕
析构函数调用完毕”
而不是上面的示例,是因为一般编译器为了提高效率会做了RVO优化(这样会更加高效,在逻辑上不出大的问题)
但是在我们的示例中是为了让大家更好的去理解这个拷贝函数的功能。
)
解释
-
func1()
:- 创建了一个
Hero
对象h1
,调用有参构造函数。 - 用
h1
初始化h2
,调用拷贝构造函数。 h1
和h2
销毁时调用析构函数。
- 创建了一个
-
func2()
:- 创建了一个
Hero
对象h1
,调用无参构造函数。 - 将
h1
传递给test1()
,调用拷贝构造函数。 - 将
h1
的地址传递给test2()
,不调用拷贝构造函数。 h1
和test1()
中的临时对象销毁时调用析构函数。
- 创建了一个
-
func3()
:test3()
中创建了一个Hero
对象h
,调用有参构造函数。h
作为返回值传递给func3()
中的h
,理论上调用拷贝构造函数,但可能被编译器优化。test3()
中创建的h
销毁时调用析构函数。- attention
(对于func3
一般编译器最终运行的结果是
“有参构造函数构造完毕
析构函数调用完毕”
而不是上面的示例,是因为一般编译器为了提高效率会做了RVO优化(这样会更加高效,在逻辑上不出大的问题)
但是在我们的示例中是为了让大家更好的去理解这个拷贝函数的功能。
)
注意: 本文是作者在学习英雄哪里来的C++面向对象的课程中创作出来的,如果有侵权请立即私信我。