http://blog.sina.com.cn/s/blog_6fd68d5f0100n60h.html

前言--构造函数、析构函数的简单理解:
1)构造函数---对象被创建时候调用的函数;
2)析构函数---对象被释放时候调用的函数;

一  案例程序源代码
//下面的代码为一个简单的VC++6.0下生成的控制台工程,自定义了一个CObj类:
#include "stdafx.h"
const int BUFFER_SIZE = 1024;//常量定义,使用const类型,尽量不要使用宏定义;
class CObj//定义类:注意尽量使用匈牙利命名法:类名以"C"为首字母,后续第一个字母大写:
{
public:
CObj()//类的构造函数;
{
//程序中使用到的常量BUFFER_SIZE,在一个固定地方定义,方便后续维护修改;
m_pszBuffer = new char[BUFFER_SIZE];//注意这是在堆上分配内存,使用数组分配;
//如果分配单个字节内存为:m_pszBuffer = new char;
};

~CObj()//类的析构函数
{
delete []m_pszBuffer;  //删除数组内存区,注意前面需要有"[]"
};
private:
char *m_pszBuffer;
};

int main(int argc, char* argv[])
{
//在栈上创建对象:obj.  (区别于堆上使用new创建对象);
CObj obj; //这一行代码在程序中运行会发生什么事情呢?Why?

CObj *pObj;  //规范的写法应该是:CObj *pObj =NULL; //why ? 防止出现野指针!
pObj = new CObj; //在堆上创建对象;

printf("Hello World!\n");

delete pObj;  //释放堆上分配的对象;
//对于栈上分配的对象obj, 程序员不用手动清除,编译器会帮我们做这个工作!
return 0;
}

二 构造函数运行机理:
1 在栈上分配对象,其构造函数会自动调用(这个过程主要靠编译程序自动编译生成其构造函数的调用代码),请看程序调试运行过程中请看:
1)设置断点:光标移到下面代码行,然后按F9(代码左边会显示一个棕色的球,表示断点加上,再按F9可以把断点去掉);
CObj obj; //这一行代码在程序中运行会发生什么事情呢?Why?
2)调试运行(按F5调试运行:前提代码编译通过才可进入调试运行模式)
3)切换到汇编模式:(在Debug工具栏上,点击“Disassembly”,切换到汇编模式,重复则切换回来源代码显示模式),显示如下:
.....
28:       //在栈上创建对象:obj.  (区别于堆上使用new创建对象);
29:       CObj obj; //这一行代码在程序中运行会发生什么事情呢?Why?
00401058   lea         ecx,[ebp-8]
0040105B   call        @ILT+15(CObj::CObj) (00401014)   //栈上创建对象obj,会自动调用类构造函数
......

30:       CObj *pObj;  //规范的写法应该是:CObj *pObj =NULL; //why ? 防止出现野指针! 
31:       pObj = new CObj; //在堆上创建对象;   //注:下面为该行源代码编译成的汇编代码。
0040107C   push        8
0040107E   call        operator new (004013c0)
00401083   add         esp,4
00401086   mov         dword ptr [ebp-20h],eax
00401089   mov         byte ptr [ebp-4],1
0040108D   cmp         dword ptr [ebp-20h],0
00401091   je          main+60h (004010a0)
00401093   mov         ecx,dword ptr [ebp-20h]
00401096   call        @ILT+15(CObj::CObj) (00401014)   //堆上new创建对象,触发构造函数调用。
0040109B   mov         dword ptr [ebp-30h],eax
0040109E   jmp         main+67h (004010a7)
004010A0   mov         dword ptr [ebp-30h],0
004010A7   mov         eax,dword ptr [ebp-30h]
004010AA   mov         dword ptr [ebp-1Ch],eax
004010AD   mov         byte ptr [ebp-4],0
004010B1   mov         ecx,dword ptr [ebp-1Ch]
004010B4   mov         dword ptr [ebp-18h],ecx

三 从以上例子可以看到
1 在汇编模式下,可以看到:
对象被创建过程(栈上创建临时对象,堆上分配对象)等,都会触发构造函数被自动调用(隐式调用,程序员看不到的);
2 这一切是如何坐到的呢?  一切都是编译器在背后支持,这是C++语言实现的基本机理!

四 关于对象的释放---析构函数
1还是上面的案例,在调试模式下运行,请看代码:
35:       delete pObj;  //释放堆上分配的对象---触发析构函数被调用!
004010C4   mov         edx,dword ptr [ebp-14h]
004010C7   mov         dword ptr [ebp-24h],edx
004010CA   mov         eax,dword ptr [ebp-24h]
004010CD   mov         dword ptr [ebp-20h],eax
004010D0   cmp         dword ptr [ebp-20h],0
004010D4   je          main+0A5h (004010e5)
004010D6   push        1
004010D8   mov         ecx,dword ptr [ebp-20h]
004010DB   call        @ILT+25(CObj::`scalar deleting destructor') (0040101e)  //调用析构函数
004010E0   mov         dword ptr [ebp-30h],eax
004010E3   jmp         main+0ACh (004010ec)
004010E5   mov         dword ptr [ebp-30h],0

36:       //对于栈上分配的对象obj, 程序员不用手动清除,编译器会帮我们做这个工作!
37:       return 0; //函数返回,触发临时对象的析构函数被调用,请看下面对应的汇编代码:
004010F7   mov         dword ptr [ebp-2Ch],0
004010FE   mov         dword ptr [ebp-4],0FFFFFFFFh
00401105   lea         ecx,[ebp-14h]
00401108   call        @ILT+10(CObj::~CObj) (0040100f)  //调用析构函数

0040110D   mov         eax,dword ptr [ebp-2Ch]
38:   }

2 总结
因此,析构函数在对象被释放时,会被调用,注意:
1)临时对象的释放调用,自动触发,不需要程序员处理---这一点是通过编译器来自动实现的!
2)堆上创建的对象(new创建),需要程序员使用delete语句释放,这也是为什么每个new对象,需要有对应delete语句的原因!(这个原因与对内存的实现机理有关,后续这方面的文章会介绍)

C++类构造函数、析构函数运行机理的更多相关文章

  1. C++ 中的类构造函数 & 析构函数

    类的构造函数 类的构造函数是类的一种特殊的成员函数,它会在每次创建类的新对象时执行. 构造函数的名称与类的名称是完全相同的,并且不会返回任何类型,也不会返回 void.构造函数可用于为某些成员变量设置 ...

  2. C++ 类构造函数 & 析构函数

    前言: 析构函数和构造函数是一对.构造函数用于创建对象,而析构函数是用来撤销对象.简单的说:一个对象出生的时候,使用构造函数,死掉的时候,使用析构函数.构造函数 和 析构函数 各有各的用途,在构造函数 ...

  3. C++ 类 & 对象-类成员函数-类访问修饰符-C++ 友元函数-构造函数 & 析构函数-C++ 拷贝构造函数

    C++ 类成员函数 成员函数可以定义在类定义内部,或者单独使用范围解析运算符 :: 来定义. 需要强调一点,在 :: 运算符之前必须使用类名.调用成员函数是在对象上使用点运算符(.),这样它就能操作与 ...

  4. 构造函数为什么不能为虚函数 & 基类的析构函数为什么要为虚函数

    一.构造函数为什么不能为虚函数 1. 从存储空间角度,虚函数相应一个指向vtable虚函数表的指针,这大家都知道,但是这个指向vtable的指针事实上是存储在对象的内存空间的.问题出来了,假设构造函数 ...

  5. C++ 派生类构造函数和析构函数

    几个问题 一个类的各数据成员的构造顺序? 按他们在类定义中出现的先后顺序:先定义者先构造. 类的对象成员的构造函数与类自身的构造函数的执行顺序? 先执行对象成员的构造函数,再执行类自身的构造函数. 构 ...

  6. C++编写字符串类CNString,该类有默认构造函数、类的拷贝函数、类的析构函数及运算符重载

    编码实现字符串类CNString,该类有默认构造函数.类的拷贝函数.类的析构函数及运算符重载,需实现以下“=”运算符.“+”运算.“[]”运算符.“<”运算符及“>”运算符及“==”运算符 ...

  7. c++学习之对象和类——构造函数和析构函数

    再认真理一遍~ 0.类 这里先来定义一个类,便于后面的理解.参考C++ Primer Plus class Stock { private: std::string company; long sha ...

  8. C++学习18 派生类的析构函数

    和构造函数类似,析构函数也是不能被继承的. 创建派生类对象时,构造函数的调用顺序和继承顺序相同,先执行基类构造函数,然后再执行派生类的构造函数.但是对于析构函数,调用顺序恰好相反,即先执行派生类的析构 ...

  9. C++构造函数/析构函数 设置成private的原因

    C++构造函数/析构函数 设置成private的原因 标签(空格分隔): c/c++ 将构造函数,析构函数声明为私有和保护的,那么对象如何创建? 已经不能从外部调用构造函数了,但是对象必须被构造,应该 ...

随机推荐

  1. 安装mosquitto报缺少dll文件的错误

    解决:下载缺少的dll组件,放到安装目录.  报错:The procedure entry point CRYPTO_memcmp could not be located in the dynami ...

  2. Several ports (8005, 8080, 8009) required

    Several ports (8005, 8080, 8009) required by Tomcat v7.0 Server at localhost are already in use. The ...

  3. SQL——登陆触发器实现限制IP

    [转载]原文地址:https://www.baidu.com/link?url=N-SM28ge21TTYky79dYk8otsjKgYCIpy-0RBSvMV25f8KSOsYczhxTOCzeNZ ...

  4. String.Format 大全

    0.0的格式化 string.Format("{0:8D8}", 3)//第一个8表示空8个位置,后一个8表示用0填写最多8位数据 1.格式化货币(跟系统的环境有关,中文系统默认格 ...

  5. 网络工程师HCNA认证学习笔记Day1

    企业网络 企业网络远程互联是广域网WAN互联,而非互联网Internet小型企业网络:一个路由器.交换机.AP大型企业网络:核心层.汇聚层.接入层.考虑可用性.稳定性.扩展性.安全性.可管理,冗余. ...

  6. lombok常用注解

    简介: Lombok能以简单的注解形式来简化java代码,提高开发人员的开发效率.例如开发中经常需要写的javabean,都需要花时间去添加相应的getter/setter,也许还要去写构造器.equ ...

  7. [Noip2012普及组]摆花

    Description 小明的花店新开张,为了吸引顾客,他想在花店的门口摆上一排花,共 m 盆.通过调查顾客的喜好,小明列出了顾客最喜欢的 n 种花,从 1 到 n 标号.为了在门口展出更多种花,规定 ...

  8. 子div块中设置margin-top时影响父div块位置的解决办法及其原因

    解决办法①: 若子DIV块中使用margin-top,则在父DIV块中添加:overflow:hidden; 解决办法②: 在子DIV块中用padding-top代替margin-top. 有个叫 b ...

  9. JSP | 基础 | 中文字符的传递

    设置传递格式: request.setCharacterEncoding("utf-8"); 中文字符解码: import java.net.URLDecoder; String ...

  10. C# 基础之类与结构体的区别

    1.语法上的区别是: 定义类使用关键字class,定义结构体用关键字struct 2.结构体中不可对声明字段进行初始化,但类可以 3. 类:如果没有为类显示的定义一个构造函数,c#编译器会自动生成一个 ...