欢迎来到CILMY23的博客
本篇主题为:C++中的构造函数和析构函数详解
个人主页:CILMY23-CSDN博客
系列专栏:Python | C++ | C语言 | 数据结构与算法
感谢观看,支持的可以给个一键三连,点赞关注+收藏。
写在前头:
本篇会从类的六个默认成员函数开始,进入构造函数和析构函数的了解。
目录
一、类的六个默认成员函数
二、构造函数
2.1 构造函数的概念
2.2 构造函数的特点
无参和有参的构造函数
2.3 随机值的初始化
三、析构函数
3.1 析构函数概念
3.2 析构函数的特点
一、类的六个默认成员函数
在上篇文章中(点击链接跳转),我们涉及到一个特殊类,这个类中什么成员都没有,其大小为1字节,我们将如果一个类中什么成员都没有,简称为空类。
例如:A1不是空类,A2是空类。
class A1{public:void f1(){}}; class A2{};
空类中真的什么都没有吗?并不是,任何类在什么都不写时,编译器会自动生成以下6个默认成员 函数。
什么是默认成员函数?
默认成员函数指的是用户没有显式实现,编译器会自动生成的成员函数称为默认成员函数。
二、构造函数
构造函数作为类默认成员函数中特殊的成员函数,是面向对象编程中非常重要的概念,那什么是构造函数呢?
2.1 构造函数的概念
现在我们有一个简易的学生类,注意,参数类型是const char*,而不是char(因为传入的参数是常量字符串,类型为const char*)
#include<iostream>using namespace std;class Student{public:void Init(const char* name,int age,const char* ID){strcpy(_name, name);_age = age;strcpy(_ID, ID);}void Print(){cout <<"学生姓名:" << _name << endl;cout <<"学生年龄:" << _age << endl;cout <<"学生学号:" << _ID << endl;}private:char _name[20];int _age;char _ID[20];};int main(){Student stu1;stu1.Init("zhangsan", 21, "20001216A11");stu1.Print();return 0;}
那我们每次初始化都要调用一个Init,或者经常忘记初始化,能否省略这个步骤呢?于是C++里就引入了构造函数这个概念。
构造函数是一个特殊的成员函数,名字与类名相同,创建类类型对象时由编译器自动调用,以保证 每个数据成员都有一个合适的初始值,并且在对象整个生命周期内只调用一次。
2.2 构造函数的特点
构造函数是特殊的成员函数,构造函数虽然名称叫构造,但是构造函数的主要任务并不是开空间创建对象,而是初始化对象。
构造函数的特点如下:
函数名与类名相同。无返回值。(无返回值不是void,而是不需要写)对象实例化时编译器自动调用对应的构造函数。构造函数可以重载。构造函数也分无参和有参数类型
无参和有参的构造函数
例如:
class Student{public://无参构造函数Student(){strcpy(_name, "xxxxxx");_age = 0;strcpy(_ID, "xxxxxxx");}//有参构造函数Student(const char*name,int age,const char* ID){strcpy(_name, name);_age = age;strcpy(_ID, ID);}void Print(){cout << "学生姓名:" << _name << endl;cout << "学生年龄:" << _age << endl;cout << "学生学号:" << _ID << endl;}private:char _name[20];int _age;char _ID[20];};int main(){Student stu1;//调用了无参的构造函数stu1.Print();Student stu2("zhangsan", 21, "20001216A11");//调用有参的构造函数stu2.Print();return 0;}
在学生类中,两个构造函数构成函数重载。在对象实例化的时候,自动调用了对应构造函数,在这个学生类,我们使用了构造函数来初始化对象,但是注意在调用无参函数的时候不加 ()。
2.3 随机值的初始化
我们说构造函数,是默认的成员函数,编译器一定会调用,但是它并没有初始化?
我们看个例子:
class Student{public:void Print(){cout << "学生姓名:" << _name << endl;cout << "学生年龄:" << _age << endl;cout << "学生学号:" << _ID << endl;}private:char _name[20];int _age;char _ID[20];};int main(){Student stu1;//调用默认的构造函数stu1.Print();return 0;}
结果:
它不是会初始化吗?但是为什么这里没有初始化,按道理来说,应该是根据类型不同,我们就直接赋值,比如,整型给0,浮点数给0.0……
其实C++把类型分成内置类型(基本类型)和自定义类型。内置类型就是语言提供的数据类型,如:int/char...,自定义类型就是我们使用class/struct/union等自己定义的类型,默认生成的构造函数,对于内置类型不做处理,自定义类型会去调用它的默认构造函数
例如:
class P{public:P(){cout << "P()" << endl;_P = 0;}private:int _P;};class Student{public:void Print(){cout << "学生姓名:" << _name << endl;cout << "学生年龄:" << _age << endl;cout << "学生学号:" << _ID << endl;}private:char _name[20];int _age;char _ID[20];P p1; //对自定义类型调用对应的默认构造函数};int main(){Student stu1;//调用默认的构造函数stu1.Print();return 0;}
C++11 中针对内置类型成员不初始化的缺陷,又打了补丁,即:内置类型成员变量在类中声明时可以给默认值。
例如:
class Student{public:void Print(){cout << "学生姓名:" << _name << endl;cout << "学生年龄:" << _age << endl;cout << "学生学号:" << _ID << endl;}private:char _name[20] = "xxxx"; //注意这里还是声明,声明给缺省值int _age = 0;char _ID[20]= "xxxxxxxx";};int main(){Student stu1;//调用默认构造函数stu1.Print();return 0;}
三、析构函数
通过前面构造函数的学习,我们知道一个对象是怎么来的,那一个对象又是怎么没呢的?
3.1 析构函数概念
析构函数:与构造函数功能相反,析构函数不是完成对对象本身的销毁,局部对象销毁工作是由 编译器完成的。而对象在销毁时会自动调用析构函数,完成对象中资源的清理工作。
3.2 析构函数的特点
析构函数是特殊的成员函数,其特点如下:
析构函数名是在类名前加上字符 ~。 无参数无返回值。 一个类只能有一个析构函数。若未显式定义,系统会自动生成默认的析构函数。注意:析构 函数不能重载 对象生命周期结束时,C++编译系统系统自动调用析构函数。学生类的析构函数:
class Student{public:void Print(){cout << "学生姓名:" << _name << endl;cout << "学生年龄:" << _age << endl;cout << "学生学号:" << _ID << endl;}~Student()//析构函数{cout << "~Student()" <<endl ;}private:char _name[20]; int _age;char _ID[20];};int main(){Student stu1;//调用默认构造函数stu1.Print();return 0;}
如果类中没有申请资源时,析构函数可以不写,直接使用编译器生成的默认析构函数,比如 Date,我们简易的学生类;有资源申请时,一定要写,否则会造成资源泄漏,比如Stack类 。
总结:
构造和析构类似初始化和销毁 构造函数的主要任务并不是开空间创建对象,而是初始化对象。 调用无参函数的时候不加 () 对象实例化的时候,一定调用构造函数,否则报错全缺省构造函数和无参可能会在调用的时候出问题,并不是不可以同时存在(构成函数重载),而是调用出现歧义无参的构造函数和全缺省的构造函数都称为默认构造函数,并且默认构造函数只能有一个。无参构造函数、全缺省构造函数、我们没写编译器默认生成的构造函数,都可以认为是默认构造函数。(一般情况写全缺省)C++11 中内置类型成员变量在类中声明时可以给默认值。 默认生成的析构函数,对于内置类型不做处理,自定义类型会去调用它的默认析构函数感谢各位同伴的支持,本期析构函数和构造函数篇就讲解到这啦,如果你觉得写的不错的话,可以给个一键三连,点赞关注+收藏,若有不足,欢迎各位在评论区讨论。