C++之构造函数与析构函数
在本篇文章中,我们将针对构造函数和析构函数的概念、用法、案例、注意事项等方面进行详细说明。C++中的构造函数和析构函数是面向对象编程(OOP)的两个非常重要特性。其中,构造函数用于在对象创建时初始化对象的属性和状态,而析构函数则用于在对象销毁时释放资源和清理状态。
构造函数的概念
构造函数(Constructor)是一种特殊的成员函数,当一个对象被创建时,它会被自动调用进行初始化操作。我们可以使用构造函数来设置对象的属性和初始状态,从而保证使用对象时可以得到正确的结果。
在C++中,每个类都可以定义一个或多个构造函数,它们之间的区别通常是在参数类型或个数上。如果我们没有显式地定义一个构造函数,则编译器会自动生成一个默认的构造函数,默认构造函数不接受任何参数,并将对象的属性设置为初始状态。但是,如果我们定义了一个构造函数,则默认构造函数将被覆盖,因此需要显式地定义一个空的默认构造函数。
析构函数的概念
析构函数(Destructor)是一种特殊的成员函数,当一个对象被销毁时自动调用。我们可以使用析构函数来释放对象所使用的资源、清理对象的状态等,从而避免出现内存泄漏和资源浪费的情况。
在C++中,每个类都可以定义一个析构函数,它的名称与类名相同,前面加上一个波浪线(~)。析构函数不接受任何参数,不返回任何值,它只是一个在对象销毁时自动调用的函数。另外,如果我们没有显式地定义一个析构函数,则编译器会自动生成一个默认的析构函数,它与默认构造函数一样,不做任何操作。
构造函数和析构函数的用法
构造函数和析构函数的主要作用是在对象创建和销毁时进行初始化和清理工作。在构造函数中,我们可以对对象的数据成员进行初始化,如设置默认值、动态分配内存等。在析构函数中,我们可以释放对象所使用的资源,如释放动态分配的内存、关闭文件等。
以下是构造函数和析构函数的简单例子:
#include <iostream>
using namespace std;
//对象的初始化和清理,都是由系统自动调用,如果程序员没有写构造和析构,系统自己会有,但是是无语句的空实现
//=================================================================
/*
1.构造函数:创建对象时,初始化操作,为对象的成员属性赋值
类名(){},没有返回值,不写void,构造函数可以有参数,可以发生重载,只需系统调用一次
2.析构函数:对象销毁前,执行一些清理工作
~类名(){},没有返回值,不写void,析构函数没有参数,不可以重载,只需系统调用一次
*/
//=================================================================
//=====================构造函数分类=================================
/*
构造函数:
分类一:无参(默认)构造和有参构造
分类二:拷贝构造和普通构造
*/
class Person
{
public:
Person() //默认(无参)构造函数
{
cout << "Person的默认构造函数" << endl;
}
Person(int a) //有参构造函数
{
cout << "Person的有参构造函数" << endl;
}
Person(const Person &p) //拷贝析构函数:相当于把Person &p 拷贝赋值给Person。不能被改变,所以类型相同,加上const,引用。
{
age = p.age;
cout << "Person的拷贝构造函数" << endl;
}
~Person()
{
cout << "Person的析构函数"<< endl;
}
int age;
};
//=====================构造函数调用=================================
//调用:括号法,显示法,隐式转换法
void test()
{
//=====括号法
Person p1; //默认调用,不要加括号,会被编译器认为成函数声明
Person p2(2); //有参调用
Person p3(p2); //拷贝调用
//====显示法
Person p4; //默认调用
Person p5 = Person(90); //有参调用
Person p6 = Person(p2); //拷贝调用
/*
Person(90);//匿名对象,不知道赋值给谁,没有名字。特点:当前执行结束后,立即被系统析构回收。
不要用拷贝函数初始化匿名对象。eg.Person(p6),这个相当于 Person p6,p6已经存在,会造成重复定义
*/
//====隐式转化法
Person p7 = 100; //有参调用
Person p8 = p7; //拷贝构造调用
}
int main()
{
test();
return 0;
}
在上面的例子中,我们定义了一个Person类,并定义了构造函数和析构函数。构造函数用于在对象创建时对年龄进行初始化操作,而析构函数用于在对象销毁时输出消息。在main函数中,我们创建了Person对象,并调用了test函数。
使用注意事项
在使用构造函数和析构函数时,需要注意以下几点:
-
一个类可以定义多个构造函数,他们之间的区别通常是在参数的类型、个数或默认值上。我们可以根据需要进行选择,并使用不同的构造函数来创建对象。
-
构造函数的调用顺序是按照成员变量在类定义中出现的顺序进行的,并且派生类的构造函数会先于基类的构造函数被调用。
-
析构函数的调用顺序与构造函数相反,并且派生类的析构函数会后于基类的析构函数被调用。
-
如果一个类中定义了析构函数,则通常也需要定义一个拷贝构造函数、拷贝赋值运算符等成员函数,用于避免深拷贝和浅拷贝等问题。
-
在构造函数和析构函数中应该注意不要发生异常,否则可能会导致未知的错误和内存泄漏等问题。
总结
构造函数和析构函数是C++中重要的特性,它们可以帮助我们在对象创建和销毁时进行初始化和清理工作。在使用时,我们需要注意构造函数的调用顺序、析构函数的调用顺序以及异常处理等问题,才能发挥它们的重要作用。希望本篇文章能对你理解和掌握构造函数和析构函数有所帮助。