目录

前言

一、类的构造函数

什么是构造函数?

构造函数的特点

构造函数的作用

二、类的析构函数

什么是析构函数?

析构函数的特点

小结

析构函数的作用

总结

结语

封面


前言

本文章将会可能会涉及到汇编的知识,不过没有关系,我会讲的尽量通俗易懂;

另外本篇文章开始前,建议了解下什么是函数重载,这个概念很简单的--有相同的函数名,但参数列表不相同的函数,就是函数重载;

一、类的构造函数

什么是构造函数?

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

        概念模糊、直接举例:

#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++】类的构造与析构相关推荐

  1. Part7 继承与派生 7.4派生类的构造和析构

    1派生类的构造函数 默认情况下:基类的构造函数不被继承,派生类需要定义自己的构造函数. C++11 规定:可用using语句继承基类构造函数.但是只能初始化从基类继承的成员.这时派生类新增成员可以通过 ...

  2. String类的构造与析构相关处理

    String类原型: 1 Class String 2 { 3 Public: 4 String(const char *str); 5 String(const String &other) ...

  3. c++基础知识点(6)类的继承,构造,析构顺序,虚继承等

    学习继承之前,我们先回顾下protected(保护)成员 protected 成员的特点与作用: -对建立其所在类对象的模块来说,它与private成员的性质相同 -对于其派生类来说,它与public ...

  4. php构造和析构方法,php5构造函数与析构函数实例

    自php5起,有了构造函数与析构函数. 这使得php更富有面向对象的魅力了. 在php4时,构造函数用的是与类同名的函数来进行构造这个动作. 例如: 复制代码 代码示例: /* * myclass.p ...

  5. 转:Delphi2010新发现-类的构造和析构函数功能

    Delphi2010发布了. 虽然凭着对Delphi的热爱第一时间就安装了,但是现在可能是年纪大了,对新事物缺乏兴趣了.一直都没有仔细研究. 今天有点时间试了一下新功能. 本来C#和Delphi.NE ...

  6. C++系列总结——构造与析构

    前言 在使用资源前,我们需要做一些准备工作保证资源能正常使用,在使用完资源后,我们需要做一些扫尾工作保证资源没有泄露,这就是构造与析构了,这和编程语言是无关的,而是使用资源的一种方式.C++只不过是把 ...

  7. (转)剖析Delphi中的构造和析构

    剖析Delphi中的构造和析构 1 Delphi中的对象模型: 2 1.1 对象名表示什么? 2 1.2 对象存储在哪里? 2 1.3 对象中存储了什么?它们是如何存储的? 3 2 构造函数与创建对象 ...

  8. C++对象模型8——构造函数和析构函数中对虚函数的调用、全局对象构造和析构、局部static数组的内存分配

    一.构造函数和析构函数中对虚函数的调用 仍然以https://blog.csdn.net/Master_Cui/article/details/109957302中的代码为例 base3构造函数和析构 ...

  9. 【设计原则和建议】 构造和析构对象

    良好的构造和析构对象,控制对象生命周期可以较大的提高程序的性能,降低GC的压力,减少BUG几率. 本文还是比较简单的,主要还是经验的总结,很多东西也许各位已经知道,也许不知道.希望大家一起讨论. 1. ...

最新文章

  1. 文档信息的向量化-词袋模型、gensim实现和词条分布
  2. 洛谷P2502:[HAOI2006]旅行
  3. C++学习笔记:(十)异常
  4. 软件测试反例,基于模型检测多反例对软件进行调试
  5. LVM--逻辑卷管理
  6. OC 中NSString与NSString 的比较
  7. transactionManager 以及datasource type解析
  8. 2 数据源配置_[Mybatis]-[基础支持层]-数据源信息-数据源详解
  9. php图片生成缩略图_php实现根据url自动生成缩略图的方法
  10. 代理模式(Proxy) 静态
  11. Log_Analysis_using_OSSEC.md
  12. 无刷直流电机常用计算公式
  13. 【编程须知】同样的代码linux与windows的运行结果不同
  14. 巨人肩膀上的迁移学习(2)---图像回归
  15. 狂神SpringBoot静态资源文件
  16. 学生对计算机课程的意见和建议怎么写,对学校的意见和建议5条怎么写
  17. vue2.x中slot-scope插槽在vue3.x中的新写法
  18. 宏病毒的研究与实例分析02——复合文档格式分析
  19. 6个开源项目提高GIS编程技能
  20. JAVA简单连接数据库(Mysql)

热门文章

  1. [Mac] 触控板鼠标点击(mouse-click)失灵
  2. elasticsearch-es查询并清理重复数据
  3. [淘宝客技术篇005]如何取站点id和推广位id
  4. ubuntu 18.04 nautilus无法显示图片、视频文件的缩略图(预览)
  5. MySQL8_基础_聚合函数
  6. php的循环有哪几种,PHP数组循环遍历的几种方式
  7. 模拟微信浏览器抓取数据
  8. Excel按单元格背景颜色查找单个单元格的2种操作
  9. java高级查询_SQL高级查询(转载)
  10. 【图形学】关于透视投影