2. 构造与析构
本篇主要解答以下问题:
- 构造函数是什么?
- 要不要写构造函数?
- 析构函数是什么?
- virtual的作用,虚析构函数的作用
2.1 构造函数
构造函数是一个名字和类相同,没有返回类型的函数,其目的是初始化对象。
C++中常见的构造函数有:
-
默认构造函数。以Student类为例,默认构造函数的原型为
代码中没有显式的定义构造函数的时候,编译器会隐式的合成默认构造函数。按类型给定初始值,初始化类成员。如果定义了构造函数则不会出现默认构造函数,若仍需要,则需明确写出,如上图的第11行。
-
初始化构造函数
一个类可以有多个构造函数,但在参数数量和参数类型上需要有所区别。初始化构造函数,如上图12行,可以直接以给定值初始化成员变量,相比于在构造函数体内赋值,省略了成员变量默认初始化这一步。
-
复制(拷贝)构造函数
复制构造函数用于复制本类的对象,大多数时候,在类中我们没有声明复制构造函数,而是C++自动为我们生成了一个复制构造函数。拷贝构造仍在构造一个新的对象,不同于赋值或引用。
class student
{
private:
int age;
int score;
public:
student() {}; //默认构造函数
student(int a, int b): age(a), score(b) {}; //初始化构造函数
};
int main() {
int a = 18, b = 85;
student s1;
student s2(a, b);
student s3(s2); //调用自动生成的复制构造函数
}
2.2 析构函数
析构函数是在对象被撤销时被自动调用, 用于对成员撤销时的一些清理工作。与构造函数相比,析构函数有如下特点:
- 析构函数函数名与类名相同, 紧贴在名称前面用波浪号 ~ 与构造函数进行区分, 例如: ~student();
- 构造函数没有返回类型, 也不能指定参数, 因此析构函数只能有一个, 不能被重载;
- 当对象被撤销时析构函数被自动调用, 与构造函数不同的是, 析构函数可以被显式的调用, 以释放对象中动态申请的内存,使用 对象名.析构函数名(); 即可。
要不要写析构函数?
当用户没有显式定义析构函数时, 编译器同样会为对象生成一个默认的析构函数, 但默认生成的析构函数只能释放类的普通数据成员所占用的空间, 无法释放通过 new 或 malloc 进行申请的空间, 因此有时我们需要自己显式的定义析构函数对这些申请的空间进行释放, 避免造成内存泄露。
2.3 虚函数与虚析构函数
虚函数的作用:
-
动态联编,当基类的指针指向子类对象时,它可以在运行时判断指针指向的对象,并自动调用相应的子类函数。不是虚函数时,则会直接调用基类函数。
参考: https://www.cnblogs.com/weiyouqing/p/7544988.html
基类的析构函数为什么要写成虚函数:
-
在删除指向子类对象的基类指针时,虚析构函数使得可以调用子类的析构函数达到释放子类中堆内存的目的,而防止内存泄露的。虚析构函数会先析构子类,在析构基类,不是虚函数时会只调用基类的析构函数,子类的内存得不到释放。
参考:https://blog.csdn.net/weicao1990/article/details/81911341