• 【C++】构造函数和析构函数第一部分(构造函数和析构函数的作用)--- 2023.9.25


    前言

    在使用c语言开发的项目场景中,我们往往会遇到申请空间的需求,同时也肯定遇到过程序运行一段时间后会卡死(崩溃)的情况,分析下来大概率可能是内存堆空间容量不够用所导致,我们作为开发人员在设计时,往往在写了malloc申请函数之后,会容易忘记释放该申请的内存堆空间。但是上述问题,往往在c++中可以得到很好解决。

    初始化和清理的概念

    1. 当对象产生时,必须初始化成员变量,当对象销毁前,必须清理对象
    2. 初始化用构造函数,清理用析构函数,这两个函数是编译器调用

    构造函数和析构函数的作用

    构造函数的作用

    先看代码:

    class Maker
    {
    public:
    	Maker()
    	{
    		a = 10;
    		cout << "构造函数" << endl;
    	}
    	
    	~Maker()
    	{
    		cout << "析构函数" << endl;
    	}
    public:
    	int a;
    };
    
    void test01()
    {
    	Maker m;
    	int b = m.a;
    	cout << b << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    好!按照老样子,接下来开始详细讲解每行代码的用处,以及为什么这样写!

    void test01()
    {
    	Maker m;
    	int b = m.a;
    	cout << b << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    Maker m;
    
    • 1

    //首先实例化对象,并且该实例化对象为m。

    int b = m.a;
    cout << b << endl;
    
    • 1
    • 2

    //将实例化对象m的成员变量a赋值给b,并且将b打印出来。

    class Maker
    {
    public:
    	Maker()
    	{
    		a = 10;
    		cout << "构造函数" << endl;
    	}
    	
    	~Maker()
    	{
    		cout << "析构函数" << endl;
    	}
    public:
    	int a;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    Maker()
    	{
    		a = 10;
    		cout << "构造函数" << endl;
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5

    //该函数即构造函数,构造函数的作用时初始化成员变量,并且是编译器自动调用的,即只要我们实例化对象之后,则编译器会自动调用构造函数进行初始化。
    //构造函数的作用其实就类似与我们使用c语言开发时使用的malloc()函数
    //在该构造函数中主要将10赋值给a。

    ~Maker()
    {
    	cout << "析构函数" << endl;
    }
    
    • 1
    • 2
    • 3
    • 4

    //该函数为析构函数,析构函数的作用其实就类似与我们使用c语言开发时使用的free()函数,所以在对象销毁前,编译器同样会自动调用析构函数。

    接下来我们看下上述代码的执行结果如何?

    在这里插入图片描述
    由上图可知 ,确实会如同我们在前面讲述一样,系统编译器会自动调用构造函数和析构函数。

    析构函数的作用

    先看代码:

    class Maker2
    {
    public:
    	Maker2(const char *name,int age)
    	{
    		cout << "有参构造" << endl;
    		pName = (char*)malloc(strlen(name) + 1);
    		strcpy(pName, name);
    		mAge = age;
    	}
    
    	void printMaker2()
    	{
    		cout << "name:" << pName << " age:" << mAge << endl;
    	}
    	~Maker2()
    	{
    		cout << "析构函数" << endl;
    		if (pName != NULL)
    		{
    			free(pName);
    			pName = NULL;
    		}
    	}
    private:
    	char *pName;
    	int mAge;
    };
    
    void test02()
    {
    	Maker2 m2("翠花",18);
    	m2.printMaker2();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    好!按照老样子,接下来开始详细讲解每行代码的用处,以及为什么这样写!

    void test02()
    {
    	Maker2 m2("翠花",18);
    	m2.printMaker2();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    //首先实例化对象,并且该实例化对象为m2
    //并且这里调用的是有参构造函数的方法,将"翠花"18作为有参构造函数的形参传进去。
    //调用类中的printMaker2函数将pNamemAge 打印出来。

    Maker2(const char *name,int age)
    {
    	cout << "有参构造" << endl;
    	pName = (char*)malloc(strlen(name) + 1);
    	strcpy(pName, name);
    	mAge = age;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    //该函数为构造函数,并且使用的和上一个程序中构造形式不同,使用的是有参构造,其中有两个形参,分别是char类型的指针变量name和int类型的age。

    pName = (char*)malloc(strlen(name) + 1);
    
    • 1

    //使用malloc函数在堆区中申请一段空间用来存放通过形参传入的name值。

    strcpy(pName, name);
    
    • 1

    //将name指向的那段内存空间的内容复制到pName指向的那段内存空间中,即pName指向的那段内存空间中存放了真正传入该函数的name值。

    mAge = age;
    
    • 1

    //简单的赋值操作。

    ~Maker2()
    {
    	cout << "析构函数" << endl;
    	if (pName != NULL)
    	{
    		free(pName);
    		pName = NULL;
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    //该函数为析构函数,在该函数中首先判断在构造函数申请的堆区空间有没有申请成功,如果申请成功,则会调用free函数去释放掉该空间,并且将其指针指向NULL。

    接下来我们看下上述代码的执行结果如何?

    在这里插入图片描述
    由上图可知 ,确实会如同我们在前面讲述一样,系统编译器会自动调用构造函数和析构函数。同时成功传入参数。

    使用构造函数和析构函数的注意事项

    1. 构造函数和析构函数的权限必须是公有的
    2. 构造函数可以重载
    3. 构造函数没有返回值,不能用void,构造函数可以有参数,析构函数没有返回值,不能用void,没有参数
    4. 有对象产生必然会调用构造函数,有对象销毁必然会调用析构函数。有多少个对象产生就会调用多少次构造函数,有多少个对象销毁就会调用多少次析构函数

    默认的构造函数和析构函数

    先看代码:

    class Maker
    {
    public:
    	Maker()//默认的构造函数,函数体是空的
    	{
    
    	}
    	~Maker()//默认的析构函数,函数体也是空
    	{
    
    	}
    	//编译器默认提供默认的构造函数和析构函数
    	void printfMaker()
    	{
    		a = 100;
    		cout << "a=" << a << endl;
    	}
    private:
    	int a;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    //即使我们在类中没有声明构造函数或者析构函数,也没关系,编译器中已经设置了默认的构造函数和析构函数,只不过在这两个函数体中都是空的,不做任何处理。

    结束语

    如果觉得这篇文章还不错的话,记得点赞 ,支持下!!!

  • 相关阅读:
    Jmeter集成到jenkins
    核心实验16_端口镜像_ENSP
    计算机网络:应用层 (DNS FTP)
    一个支持IPFS的电子邮件——SKIFF
    Java 8中的map和flatMap方法的区别
    第七章 块为结构建模 P2|系统建模语言SysML实用指南学习
    mysql5.7.35安装配置教程【超级详细安装教程】
    Leetcode 76. 最小覆盖子串
    配置文件生成器-秒杀SSM的xml整合
    【面试系列】Java面试知识篇(二)
  • 原文地址:https://blog.csdn.net/qq_40544107/article/details/132585294