C++类构造函数、析构函数运行机理
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++类构造函数、析构函数运行机理的更多相关文章
- C++ 中的类构造函数 & 析构函数
类的构造函数 类的构造函数是类的一种特殊的成员函数,它会在每次创建类的新对象时执行. 构造函数的名称与类的名称是完全相同的,并且不会返回任何类型,也不会返回 void.构造函数可用于为某些成员变量设置 ...
- C++ 类构造函数 & 析构函数
前言: 析构函数和构造函数是一对.构造函数用于创建对象,而析构函数是用来撤销对象.简单的说:一个对象出生的时候,使用构造函数,死掉的时候,使用析构函数.构造函数 和 析构函数 各有各的用途,在构造函数 ...
- C++ 类 & 对象-类成员函数-类访问修饰符-C++ 友元函数-构造函数 & 析构函数-C++ 拷贝构造函数
C++ 类成员函数 成员函数可以定义在类定义内部,或者单独使用范围解析运算符 :: 来定义. 需要强调一点,在 :: 运算符之前必须使用类名.调用成员函数是在对象上使用点运算符(.),这样它就能操作与 ...
- 构造函数为什么不能为虚函数 & 基类的析构函数为什么要为虚函数
一.构造函数为什么不能为虚函数 1. 从存储空间角度,虚函数相应一个指向vtable虚函数表的指针,这大家都知道,但是这个指向vtable的指针事实上是存储在对象的内存空间的.问题出来了,假设构造函数 ...
- C++ 派生类构造函数和析构函数
几个问题 一个类的各数据成员的构造顺序? 按他们在类定义中出现的先后顺序:先定义者先构造. 类的对象成员的构造函数与类自身的构造函数的执行顺序? 先执行对象成员的构造函数,再执行类自身的构造函数. 构 ...
- C++编写字符串类CNString,该类有默认构造函数、类的拷贝函数、类的析构函数及运算符重载
编码实现字符串类CNString,该类有默认构造函数.类的拷贝函数.类的析构函数及运算符重载,需实现以下“=”运算符.“+”运算.“[]”运算符.“<”运算符及“>”运算符及“==”运算符 ...
- c++学习之对象和类——构造函数和析构函数
再认真理一遍~ 0.类 这里先来定义一个类,便于后面的理解.参考C++ Primer Plus class Stock { private: std::string company; long sha ...
- C++学习18 派生类的析构函数
和构造函数类似,析构函数也是不能被继承的. 创建派生类对象时,构造函数的调用顺序和继承顺序相同,先执行基类构造函数,然后再执行派生类的构造函数.但是对于析构函数,调用顺序恰好相反,即先执行派生类的析构 ...
- C++构造函数/析构函数 设置成private的原因
C++构造函数/析构函数 设置成private的原因 标签(空格分隔): c/c++ 将构造函数,析构函数声明为私有和保护的,那么对象如何创建? 已经不能从外部调用构造函数了,但是对象必须被构造,应该 ...
随机推荐
- C++多态性:虚函数的调用原理
多态性给我们带来了好处:多态使得我们可以通过基类的引用或指针来指明一个对象(包含其派生类的对象),当调用函数时可以自动判断调用的是哪个对象的函数. 一个函数说明为虚函数,表明在继承的类中重载这个函数时 ...
- Cookie和Session(3)
关于Cookie和Session Cookie和Session都为了用来保存状态信息,都是保存客户端状态的机制,它们都是为了解决HTTP无状态的问题而所做的努力. 1)cookie 是一种发送到客户浏 ...
- Tessellation
Tessellation细分曲面技术是AMD(ATI)常年研发多代的技术,经过多年发展最终被采纳成为DX11的一项关键技术,因此历来都是宣传重点.和光线追踪不同,现在的光栅化图形渲染技术的核心是绘制大 ...
- [Xcode 实际操作]二、视图与手势-(5)给图像视图添加圆角效果
目录:[Swift]Xcode实际操作 本文将演示给矩形图片添加圆角效果 import UIKit class ViewController: UIViewController { override ...
- IT兄弟连 JavaWeb教程 Servlet会话跟踪 经典面试题
1.描述Cookie的作用 Cookie是网站保存在浏览器客户端的信息,也就是说保存在访客的机器里的变量,一般随着HTTP头发送到客户端.在Cookie生效之后及失效之前,客户每次发出页面请求的时候, ...
- 阿里云物联网 .NET Core 客户端 | CZGL.AliIoTClient:2. IoT 客户端
文档目录: 说明 1. 连接阿里云物联网 2. IoT 客户端 3. 订阅Topic与响应Topic 4. 设备上报属性 4.1 上报位置信息 5. 设置设备属性 6. 设备事件上报 7. 服务调用 ...
- (转)java 线程同步
转自 http://blog.csdn.net/column/details/java-thread.html http://leo-faith.iteye.com/blog/177779 http: ...
- [LOJ#10042] 收集雪花
题目链接: 点我 题目分析: 双指针扫描可以保证在\(O(n)\)的时间复杂度内处理这道题.另外,虽然这个题标签是\(hash\),但是字符串\(hash\)是可以卡掉的,所以建议直接离散化. 维护两 ...
- MFC中的模态对话框与非模态对话框
模态对话框创建: MyDialog mydlg; mydlg.DoModal() 当前只能运行此模态对话框,且停止主窗口的运行,直到模态对话框退出,才允许主窗口运行. 模态对话框的关闭顺序: OnCl ...
- HTML的基础结构
<html>内容</html> 解释:HTML文档的文档标记,也称为HTML开始标记 功能:这对标记分别位于网页的最前端和最后端 <head>内容</head ...