具体有:
- 这六个默认构造函数都是特殊的成员函数,我们所熟知的函数的特性与它们有很大不同。
2. 构造函数
2.1 概念
构造函数是c++里类的一种特殊成员函数,它在创建该类的新对象时自动调用,主要用于初始化对象的数据成员和分配必要的资源。
构造函数的目的是为了替代 Init 函数(初始化函数)。凭它自动调用的特性,可以很好的避免我们在写代码时忘记对对象进行初始化。
2.2 特点
自动调用:不用传实参 显式调用:需要传参
- 名称与类名相同。
- 无返回值(也不用写void, c++规定如此)。
- 接受函数重载,这代表我们可以设置多个默认构造函数,根据要求,用来应对不同的情况。
代码语言:javascript
AI代码解释
class Date { public: Date()//无参构造函数 { _year = 1; _month = 1; _day = 1; } Date(int year, int month, int day)//带参构造函数 { _year = year; _month = month; _day = day; } void Print() { cout << _year << "年" << _month << "月" << _day << "日" << endl; } private: int _year; int _month; int _day; }; int main() { Date d1;//自动调用 Date d2(2025, 5, 8);//显式调用 d1.Print(); d2.Print(); return 0; }- 小点:自动调用构造函数时,不能加括号,如下图,若我要定义一个返回值类型为 Date 的函数 func,你能找到它们形式的不同点吗?
在这里插入图片描述
所以,c++规定,不能够加括号哦!
- 若用户未显式定义构造函数,那么将由c++编译器自动生成一个无参的默认构造函数,一旦用户显示定义,编译器将不再生成。
- 默认构造函数只包含三类:无参构造函数、全缺省构造函数和由系统自动生成的一个无参默认构造函数。这三者只能存在一个,它们不能同时存在。
默认构造函数 != 只有系统生成的默认构造函数–>总结:不用传实参就可以调用的函数就是默认构造函数。
- 能够被自动调用的只有不用传实参的默认构造函数。其它的都是显式调用。
代码语言:javascript
AI代码解释
class Date { public: Date()//无参构造函数 { _year = 1; _month = 1; _day = 1; } Date(int year = 1, int month = 1, int day = 1)//全缺省构造函数 { _year = year; _month = month; _day = day; } void Print() { cout << _year << "年" << _month << "月" << _day << "日" << endl; } private: int _year; int _month; int _day; }; int main() { Date d1; d1.Print(); return 0; }- 能被自动调用的就只有默认成员函数(不用传参),也就是 5 中提到的三个,那么像是我们上面代码中所写的带参构造函数它就不能被自动调用,即我们需要传参使用(显式调用)。
- 三者只能存在一个也可以这样理解:这三个默认成员函数除了第三个是因为用户不显式定义才会存在之外,前两个不能同时存在的原因就是,自动调用不用传参,那么我们在实例化对象的时候如何知道调用的究竟是哪一个?而编译器它也不知道。
就会有:
在这里插入图片描述
在这里插入图片描述
- 我们接下来仔细研究一下由系统生成的无参的默认构造函数,利用日期类和 Stack类还有 MyQueue类(由栈来实现的队列)来理解:
代码语言:javascript
AI代码解释
//日期类 class Date { public: private: int _year; int _month; int _day; }; //Stack类 typedef int STDataType; class Stack { public: Stack(int n = 4) { STDataType* tmp = (STDataType*)malloc(sizeof(STDataType) * n); if (tmp == nullptr) { perror("malloc fail"); exit(1); } _arr = tmp; _top = 0; _capacity = n; } private: STDataType* _arr; int _top; int _capacity; }; //MyQueue类 class MyQueue { public: private: Stack s1; Stack s2; }; int main() { Date d; Stack stack; MyQueue myqueue; return 0; }在这里插入图片描述
在这里插入图片描述
- 我们能够发现,编译器没有对d 的成员变量进行初始化,这是因为编译器对内置类型初始化没有要求,也就是是否初始化我们不知道,具体的要看编译器。那么什么是内置类型?
c++将类型分为内置类型(基本类型)和自定义类型,内置类型就是语言提供的原生数据类型,如:int / double / long / char /指针等。自定义类型就是我们使用 class / struct 等关键字自己定义的类型。
- 我们还能够发现,跟Stack类不一样,我们没有给 MyQueue 类显式定义构造函数,可为什么编译器能够正常对 MyQueue 类成员变量正常初始化呢?这是因为:MyQueue 类的成员变量都是其他类的对象,在这种时候,这些成员对象的构造函数会被自动调用(无参数时)或者我们传递实参显式调用。
- 那么我们什么时候需要自己写构造函数呢?
大多数情况下都需要我们主动显式写构造函数,只有像 MyQueue 类这样成员对像的构造函数能被正常调用时
3. 析构函数
3.1 概念
析构函数是面向对象编程中类的一个特殊成员函数,用于在对象生命周期结束时自动执行资源清理工作。不是销毁而是清理,对象的销毁(内存回收)由系统自动完成,而析构函数只是在此过程之中插入一个清理步骤。
构造函数的目的是为了替代 Destory 函数(销毁函数)。凭它自动调用的特性,可以很好的避免我们在写代码时忘记对对象进行清理。
3.2 特点
- 析构函数名是在类名之前加上一个 字符 ‘~’。
- 无参数无返回值。
- 一个类只能存在一个析构函数。如果未显式定义,系统会自动生成一个默认的析构函数。
- 在对象生命周期结束后,会自动调用析构函数。