我的编程空间,编程开发者的网络收藏夹
学习永远不晚

C++类的构造与析构特点及作用详解

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

C++类的构造与析构特点及作用详解

一、类的构造函数

什么是构造函数

和类具有相同名称,并且没有返回值类型的函数,就是类的构造函数

概念模糊、直接举例:

#include <stdio.h>
#include <windows.h>
struct Test
{
    Test()        // 和类具有相同的名、并且没有返回值
    {
    }
};
int main()
{
    return 0;
}

构造函数的特点

直接先来说特点吧,然后论证:

1、构造函数在定义对象的时候被调用

2、构造函数可以进行函数重载,可以有很多个

3、创建对象时默认调用的是无参构造

证明1:

构造函数在定义对象的时候被调用;

论证如下:

#include <stdio.h>
struct Test
{
	Test()
	{
		printf("你调用了构造函数\n");		// 此处下断点、如果该函数被调用肯定会停下来。
	}
};
int main()
{
	Test te;
	printf("接力\n");
	return 0;
}

我们在Test()构造的输出语句上加断点、当程序调用Test的printf肯定会停下来,这个时候我们转到反汇编,单步步过、直到函数返回之后,就能知到刚刚是在哪里调用的构造函数了

vs2010:F7编译、F5调试、ALT+8反汇编:

F10一直运行到返回:

这里编译器做了优化,可以直接看出来是在Test定义对象的时候调用了构造。

证明2:

构造函数可以进行函数重载,可以有很多个;

论证如下:

#include <stdio.h>
#include <Windows.h>
struct Test
{
	Test()
	{
		printf("你调用了构造函数\n");		// 此处下断点、如果该函数被调用肯定会停下来。
	}
	Test(int a)
	{
		printf("重载%d\n",a);
	}
	Test(int a, int b)
	{
		printf("重载%d\n",a+b);
	}
};
int main()
{
	Test te;
	Test te1(1);
	Test te2(1,1);			// 注意、调用有参的构造函数时,需要传递参数
	system("pause");
	return 0;
}

重载了两个,注意:调用有参数的构造时,需要传递参数。

运行可以通过:

证明3:

创建对象时默认调用的是无参构造;

论证如下:

#include <stdio.h>
#include <Windows.h>
struct Test
{
	Test(int a)
	{
		printf("重载%d\n",a);
	}
	Test(int a, int b)
	{
		printf("重载%d\n",a+b);
	}
};
int main()
{
	Test te;            // 普通定义对象的方式、不带参数
	system("pause");
	return 0;
}

首先我们删除无参构造,看看能否编译通过:

不可以

然后删除有参构造:

#include <stdio.h>
#include <Windows.h>
struct Test
{
	Test()
	{
		printf("你调用了构造函数\n");		// 此处下断点、如果该函数被调用肯定会停下来。
	}
};
int main()
{
	Test te;
	system("pause");
	return 0;
}

可以

全部都加上:

#include <stdio.h>
#include <Windows.h>
struct Test
{
	Test()
	{
		printf("你调用了构造函数\n");		// 此处下断点、如果该函数被调用肯定会停下来。
	}
	Test(int a)
	{
		printf("重载%d\n",a);
	}
	Test(int a, int b)
	{
		printf("重载%d\n",a+b);
	}
};
int main()
{
	Test te;
	system("pause");
	return 0;
}

运行结果:

这已经证明了,Test te;平常这样定义对象的时候,调用的是无参构造。如果需要调用有参构造,必须传入参数;

这个特点很简单、有参函数肯定要传参嘛,所以定义对象的时候肯定要传入参数啊;

但是这里建议无论什么时候写类,最好还是写上无参构造,哪怕什么都不做也尽量写上,避免不必要的麻烦。

构造函数的作用

一般用于初始化类的成员

如下:

#include <stdio.h>
#include <Windows.h>
struct Test
{
	int x;
	int y;
	int z;
	Test()
	{
	}
	Test(int x,int y,int z)						// 构造函数初始化对象
	{
		this->x = x;
		this->y = y;
		this->z = z;	
	}
};
int main()
{
	Test te;
	Test te1(1,2,3);							// 定义对象并调用有参构造进行初始化
	printf("%d %d %d\n",te1.x,te1.y,te1.z);		// 输出看看是否初始化成功
	system("pause");
	return 0;
}

运行如下:

初始化成功。

二、类的析构函数

什么是析构函数

类的构造函数名前加上'~'这个符号,就是类的析构函数

概念模糊、代码如下:

#include <stdio.h>
#include <Windows.h>
struct Test
{
	Test()
	{
		printf("你调用了一次类的构造函数\n");
	}
	~Test()
	{
		printf("你调用了一次类的析构函数\n");
	}
};
int main()
{
	Test te;
	// system("pause");        // 这里就不要让程序停下来了,不然析构不了
	return 0;
}

~Test(){}就这个样子

析构函数的特点

依然直接先来说特点,然后论证:

1、析构函数不能重载、不能有参数

2、析构函数在变量声明周期结束时被调用

3、析构函数被调用分两种情况:堆栈中定义的对象、全局区中定义的对象

证明1:

析构函数不能重载、不能有参数;

编译不通过。

既然不能有参数,那重载更不可能了

证明成功。

证明2:

析构函数在变量声明周期结束时被调用;

局部变量的生命周期是在一个大括号内,即一个所处块结束。

所以:

#include <stdio.h>
#include <Windows.h>
struct Test
{
	Test()
	{
		printf("你调用了一次类的构造函数\n");
	}
	~Test()
	{
		printf("你调用了一次类的析构函数\n");
	}
};
int main()
{
	{
		Test te;
		printf("te生命周期即将结束。\n");
	}                                    // 析构应该在这里被调用
	printf("te生命周期结束。\n");
	system("pause");
	return 0;
}

运行结果如下:

断点

结果

证明成功。

证明3:

析构函数被调用分两种情况:堆栈中定义的对象、全局区中定义的对象;

已知堆栈中定义的对象(局部变量)在块语句结束之后就会被调用,那么带有return的main函数是在返回前调用析构,还是返回后呢?

代码如下:

#include <stdio.h>
#include <Windows.h>
struct Test
{
	Test()
	{
		printf("你调用了一次类的构造函数\n");
	}
	~Test()
	{
		printf("你调用了一次类的析构函数\n");			// 断点--汇编
	}
};
int main()
{
	Test te;
	// system("pause");					// 不要使用pause,不然无法返回
	return 0;
}

断点-调试-汇编:

可以看到是在函数返回前被调用的。

如果在全局区定义的对象呢?

这个问题很难说,像我一样定义两个断点就行了,如下:

#include <stdio.h>
#include <Windows.h>
struct Test
{
	Test()
	{
		printf("你调用了一次类的构造函数\n");
	}
	~Test()                                    // 断点
	{
		printf("你调用了一次类的析构函数\n");			
	}
};
Test te;
int main()
{
	// system("pause");					// 不要使用pause,不然无法返回
	return 0;                           // 断点
}

运行:

发现一运行就断在了return,当我们发F10继续运行的时候,并没有直接调用析构,而是到了括号那里:

继续F10:

通过翻译,可以得知这就是进程结束时的一些收尾工作。

继续F10:

现在大概可以总结了,类的对象定义为全局变量时,是在main函数结束之后进程退出之前,调用的析构函数。

小结

当类的对象定义为局部变量时(堆栈),定义这个对象的块作用域结束时就会调用该对象的析构函数,如果在main函数这个块作用域中定义的对象,那么就是在return之前调用析构。

当类的对象定义为全局变量时(全局区),会在main函数return函数返回之后和进程结束之前,调用该对象的析构函数。

析构函数的作用

我们知道了析构函数都是在类的对象生命周期结束时被调用,那么就代表下面不会再使用到这个对象;所以析构函数一般用于一些收尾的工作,以防忘记。

比如当你使用了该对象的成员申请了内存(malloc、new等)、或者open了一些文件,那么可以在析构函数中free delete 或者close。

例如:

#include <stdio.h>
#include <Windows.h>
struct Test
{
	int x;
	char* name;
	Test()
	{
		name = (char*)malloc(sizeof(char)*20);        // 构造时动态申请
	}
	~Test()
	{
		if(this->name!=0)                             // 析构时判断是个否为空,不为空释放
		{
			free(name);
			name = 0;
		}
	}
};
int main()
{
	Test te;
	return 0;
}

这里我就不运行了,大家可以自己测试下。

总结

构造函数

1、和类具有相同名称,并且没有返回值类型的函数,就是类的构造函数

2、构造函数在定义对象的时候被调用

3、构造函数可以进行函数重载,可以有很多个

4、创建对象时默认调用的是无参构造

析构函数

1、类的构造函数名前加上'~'这个符号,就是类的析构函数

2、析构函数不能重载、不能有参数

3、析构函数在变量声明周期结束时被调用

4、析构函数被调用分两种情况:堆栈中定义的对象、全局区中定义的对象

到此这篇关于C++类的构造与析构特点及作用详解的文章就介绍到这了,更多相关C++类的构造与析构内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

C++类的构造与析构特点及作用详解

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

C++类的构造与析构特点及作用详解

本文章将会可能会涉及到汇编的知识,不过没有关系,我会讲的尽量通俗易懂;另外本篇文章开始前,建议了解下什么是函数重载,这个概念很简单的--有相同的函数名,但参数列表不相同的函数,就是函数重载
2022-11-13

C++类与对象及构造函数析构函数基础详解

这篇文章主要为大家介绍了C++类与对象及构造函数析构函数基础详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2023-05-16

C++类的对象作类成员调用构造、析构函数及静态成员实例分析

这篇文章主要介绍了C++类的对象作类成员调用构造、析构函数及静态成员实例分析的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇C++类的对象作类成员调用构造、析构函数及静态成员实例分析文章都会有所收获,下面我们一起
2023-06-30

【Java基础教程】(七)面向对象篇 · 第一讲:上干货!面向对象的特性、类与对象、内存结构引用分析、垃圾收集器 GC处理、封装性详解、构造方法、匿名对象、简单 Java 类~

Java基础教程之面向对象 · 第一讲 🍉 篇章介绍本节学习目标1️⃣ 面向对象的三个特性2️⃣ 类与对象2.1 基本概念2.2 定义 3️⃣ 引用分析🔍 关于`垃圾收集器 GC`处理的介绍
2023-08-19

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录