【汇编 C++】类的构造与析构_c++构造类-程序员宅基地

技术标签: C++  汇编  c++  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、析构函数被调用分两种情况:堆栈中定义的对象、全局区中定义的对象

结语

        作者水平不高、如有错还望指出;如有听不懂的地方,可以私信或评论,之后会更改

封面

 

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_52572621/article/details/127220285

智能推荐

Bug的生命周期状态流程图_bug生命周期流程图-程序员宅基地

文章浏览阅读4.3k次,点赞2次,收藏8次。bug的生命周期BUG的生命周期,就是一个BUG被发现到这个BUG被关闭的过程。生命周期中缺陷状态:新建-->指派-->已解决-->待验-->关闭发现BUG-->提交BUG-->指派BUG-->研发确认BUG-->研发去修复BUG-->回归验证BUG-->是否通过验证-->关闭BUG如果待验的BUG在验证时没有解决好,我们需要重新打开--指派—已解决—待验,循环这个过程。中间其他状态:拒绝、延期等_bug生命周期流程图

Pandas对行/列求和_pandas对具体列求和-程序员宅基地

文章浏览阅读5.3k次,点赞3次,收藏18次。Pandas对行/列求和_pandas对具体列求和

Visio--用例图、类图、顺序图、活动图_visio画用例图-程序员宅基地

文章浏览阅读1.9w次,点赞32次,收藏228次。做个小结。_visio画用例图

程序员的路----程序员一定要仔细看_程序员的道路-程序员宅基地

文章浏览阅读2.2k次。在网上看到的恶搞程序员的图片,实在是搞笑。看一次笑一次!程序猿的十年他不是乞丐,请尊称他为程序猿。对,他就是程序猿!其实,你们看到的不是僵尸,他们都是苦逼的程序猿!这不是恶搞的,是一个真实的故事!看他的拐杖,其实也挺可怜的!不知是不是敲代码敲多了,把脚敲颓了!_程序员的道路

从Atlas到Microsoft ASP.NET AJAX(6) - Networking, Application Services-程序员宅基地

文章浏览阅读42次。NetworkingCalling Web Service Methods from Script  为了简化Web Services方法调用,客户端代理的设计被改变了,它在方法调用和回调函数设置方面提供了强大的灵活性。  下面的例子展示了CTP版本中Web Services方法的客户端调用,以及回调函数的使用方式。第一个例子展示了在CTP版本中Web ..._.net6 applicationservices

一文带你了解socket网络编程以及详解过程和原理_socket编程-程序员宅基地

文章浏览阅读1.1w次,点赞42次,收藏178次。Socket(套接字)是计算机网络编程中的一种抽象概念,它提供了在网络上进行通信的接口。通过使用 Socket,可以在不同计算机之间建立连接,并进行数据的传输和交换。通过 Socket,客户端可以与服务器建立连接并发送请求,服务器接收请求并返回响应。通过 Socket,可以在多个用户之间实现实时的文字、音频或视频通信。可以使用 Socket 在不同计算机之间传输文件,如上传和下载文件。可通过 Socket 在远程计算机上执行指令或操作。_socket编程

随便推点

计算机考研408每日一题 day78_命中率高且电路实现简单的cache内存映射方式-程序员宅基地

文章浏览阅读392次。对于二叉排序树,下面的说法 ___是正确的。(华南理工大学 2006年)设备驱动程序在读写磁盘数据时一般釆用下列哪种I/O方式?(中国科学院大学 2018)下列___交换技术是独占信道工作方式。(中南大学 2006年)命中率高且电路实现简单的Cache 与内存映射方式是___映射方式。(中国科学院大学 2015)_命中率高且电路实现简单的cache内存映射方式

Unhandled exceptions: java.lang.IllegalAccessException, java.lang.reflect.InvocationTargetException_unhandled exceptions: java.lang.instantiationexcep-程序员宅基地

文章浏览阅读3.2k次。可能是没有异常处理,只需要加上throws Exception就解决问题了。_unhandled exceptions: java.lang.instantiationexception, java.lang.illegalacc

webview ERROR_UNSUPPORTED_SCHEME ,errorcode=-10问题处理-程序员宅基地

文章浏览阅读1.5k次。webView.setWebViewClient(new WebViewClient(){ @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { try{ if(url.startsWith("baidumap://")){ Intent _error_unsupported_scheme

embed标签-程序员宅基地

文章浏览阅读66次。Embed  (一)、基本语法:  embed src=url  说明:embed可以用来插入各种多媒体,格式可以是 Midi、Wav、AIFF、AU、MP3等等, Netscape及新版的IE 都支持。url为音频或视频文件及其路径,可以是相对路径或绝对路径。  示例:<embed src="your.mid">  (二)、属性设置:  1、自动播放...

php 上传文件漏洞,PHP -- 文件包含、文件上传漏洞-程序员宅基地

文章浏览阅读330次。PHP -- 文件包含、文件上传漏洞PHP -- 文件包含、文件上传漏洞文件包含文件引入漏洞,是由一个动态页面编译时引入另一个文件的操作。文件引入本身是没有问题,它是用于统一页面风格,减少代码冗余的一种技术。但是在特定的场景下就会形成漏洞jsp:include指令和include动作,其中include动作用于引入动态文件php:include(),include_once(),require()..._php文件上传4漏洞

配置NGINX同时运行 https 和 http_nginx 和 http无法同时启动-程序员宅基地

文章浏览阅读406次。SSL 是需要申请证书的,key和PEM文件要放到服务器路径。然后NGINX下要进行443端口和80端口的绑定。server { listen 80; server_name ietaiji.com www.ietaiji.com; root "D:/aaa/WWW/ietaiji"; index index.html_nginx 和 http无法同时启动