看了不少C++书,当讲到静态变量的时候,总是以int成员来举例,是啊,这样很好理解。但是如果这个静态变量是一个对象行不行呢?不仅行,有时候还非常必要,而且别有洞天。

比如:

// .h 文件
class SystemGlobal
{
public:
static ConfigXML* m_pInstance;
}
// .cpp 文件
ConfigXML* SystemGlobal::m_pInstance = new ConfigXML();
SystemGlobal::SystemGlobal(void)
{
}

那么应该何时删除这个对象呢?想了很久,一开始觉得应该是在main()函数里,我这是还是QT程序,不得不改写了main()函数通常的return 方式,变成这样:

    MainWidget main_widget;
main_widget.showWidget(); int ret = app.exec();
delete SystemGlobal::m_pInstance;
return ret;

我试了试,程序可以正常退出。反正我试了5遍都没有问题。普通C++程序没有app.exec的困扰,应该更加没有问题。

---------------------------------------------------------

然后我又在网上搜了搜(很难搜到啊),受这个帖子启发:
http://bbs.csdn.net/topics/200006181
改成在拥有静态变量对象的类析构函数里删除它,如下:

SystemGlobal::~SystemGlobal(void)
{
delete SystemGlobal::m_pInstance;
}

同样试了5次,也没有问题。

但是我觉得这种方法不好,因为万一SystemGlobal在整个项目中有多个实例呢,难道销毁一个实例的时候,就必须销毁这个静态对象?这种方法只适合于整个项目就这一个SystemGlobal实例的情况。而且析构函数不允许重载和参数,就显得更加有问题了。

---------------------------------------------------------

最后要提一句,静态变量对象的初始化不仅仅别有洞天,而且实际上是相当重要的,因为它会在main()函数开始前执行,这代表什么?代表在main()函数的第一句语句执行之前,已经执行过这个静态变量对应的类的构造函数了,而构造函数本身可以执行无穷无尽的语句,相当于main()函数只是一个正房,在正房出现前,程序员已经与小三天翻地覆一番后才回来了(真是经典案例!),而且这个小三仍存在于内存之中,与正房并列。

不要奇怪,其实MFC的执行流程就是从CMyApp(继承于CWinApp)的theApp实例生成的过程开始的(注意,theApp不是静态变量对象,但却是一个写在.cpp文件中的全局对象,其实与静态变量对象也没有什么本质的区别,也正因为theApp对象的指针仍需要被获取,但又没有静态变量那么方便,所以微软专门提供了AfxGetApp()全局函数。但是为什么提供这个函数,而不是使用静态变量对象呢?我觉得2个原因,1是静态变量名称又臭又长,2是函数具有更好的封装性,可以做更多的检查乃至偷天换日):

MyApp::MyApp()
{ // 断点2,在括号这行下断点
} MyApp theApp; // 断点1,在这行也下断点 BOOL MyApp::InitInstance()
{
}
// 断点3,手动打开appmodul.cpp文件,然后在_tWinMain的括号处下断点
extern "C" int WINAPI
_tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,__in LPTSTR lpCmdLine, int nCmdShow)
{
return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
}

执行,通过追踪MFC源代码,可以发现程序首先定位于断点1,按F11追踪,发现会落在断点2。继续按F11,会发现执行CWinApp::CWinApp(LPCTSTR lpszAppName),然后按F10,发现会执行一大堆语句才会返回。可见的确实别有洞天。做完这些事情以后,就开始执行WinMain函数了(断点3),具体可以发现WinMain函数是在appmodul.cpp文件中。

读书笔记,两种效果:1. 在MFC初始化完成后,WinMain被自动调用,两者就相互联系起来了 2. MFC没有也不可能封装WinMain函数(有待进一步阐述)

参考:
http://www.cnblogs.com/zhili/p/mfcanalyze.html
http://www.moon-soft.com/program/bbs/readelite9623.htm

http://www.cnblogs.com/suncoolcat/p/3367627.html

http://www.xuebuyuan.com/2119787.html (彩色贴图,比较清楚)

http://cnmqw.iteye.com/blog/1921782 (精简了代码,非常清楚)

C++静态变量对象的建立和删除,兼论MFC开始运行的起点(全局对象)的更多相关文章

  1. 全局对象Application的使用,以及如何在任何地方得到Application全局对象

    Application和Activity,Service一样是android框架的一个系统组件,当android程序启动时系统会创建一个application对象,用来存储系统的一些信息.通常我们是不 ...

  2. Java 局部变量、实例变量、类变量(静态变量)区别

    1. 局部变量: 局部变量是类的方法中的变量: 2. 实例变量: 实例变量也是类中独立于方法之外的变量,不过没有static修饰,也叫 对象变量 3. 类变量(静态变量): 类变量是类中独立于方法之外 ...

  3. [ 转载 ]Java:成员变量,局部变量,静态变量的区别

    精简后方便自己理解. 成员变量 我们研究一个事物: 属性:外在特征:如身高,体重 行为:能做什么:如说话,打球. 在Java语言中,最基本的单位是类(class),类就是用来体现事物的. 属性:类中的 ...

  4. 1.7Oob 静态变量静态方法

    1)静态方法中可以直接调用同类中的静态成员,但不能直接调用非静态成员 2)如果希望在静态方法中调用非静态变量,可以通过创建类的对象,然后通过对象来访问非静态变量. 3)静态方法中不能直接调用非静态方法 ...

  5. 成员变量(实例变量)&局部变量&静态变量(类变量)的区别

    成员变量(实例变量)&局部变量区别: (1)作用域 成员变量:针对整个类有效. 局部变量:只在某个范围内有效.(一般指的就是方法,语句体内) (2)存储位置 成员变量:随着对象的创建而存在,随 ...

  6. 谈谈java中静态变量与静态方法在有继承关系的两个类中调用

    谈谈java中静态变量与静态方法在有继承关系的两个类中调用 学习的中如果遇到不明白或者不清楚的的时候,就是自己做些测试,自己去试试,这次我就做一个关于静态变量和静态方法在有继承关系的两个类中的问题测试 ...

  7. java 静态变量&静态方法

    1. 静态变量是static修饰的成员变量(类变量),若无static修饰,则是实例变量.静态变量是一种全局变量,它属于某个类,不属于某个对象实例,是在各对象实例间共存.   访问静态变量直接通过类名 ...

  8. JavaScript中hoisting(悬置/置顶解析/预解析) 实例解释,全局对象,隐含的全局概念

    JavaScript中hoisting(悬置/置顶解析/预解析) 实例解释,全局对象,隐含的全局概念 <html> <body> <script type="t ...

  9. JavaScript 全局对象

    全局属性和函数可用于所有内建的 JavaScript 对象. 顶层函数(全局函数) 函数 描述 decodeURI() 解码某个编码的 URI. decodeURIComponent() 解码一个编码 ...

随机推荐

  1. 解决无法获取 GridView 隐藏列值问题

    今天遇到了一个要获取GridView隐藏列值的问题,试了好几种方法,要么获取不到,要么获取到了类列的值也隐藏了,但在样式中这一列会多出一块,,但最后找到了一个功能实现而且实现了列完美隐藏的方法和大家分 ...

  2. 启用aspnet

    1. 进入dotnetfw目录 cd C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727 2. aspnet_regiis -i -enable

  3. ng1中 如何用双向绑定 实现单向绑定的初始时不显示双括号效果?

    ng1中 如何用双向绑定 实现单向绑定(ng-bind就可以不显示{{}})的初始时不显示双括号效果? AngularJS 实例 页面加载时防止应用闪烁: <div ng-app="& ...

  4. VS2010数据库连接问题

    我用SQL server 2008写了一个小表格,运行VS的前选择了 工具-连接数据库,然后选择了那个表格的名称.运行后出现如下错误提示,请问是哪里出了问题呢? 数据库连接版本有问题.在VS中把信用数 ...

  5. Solr使用初探——Solr的安装环境与配置

    Solr是一个apache名下很好用的开源索引.搜索工具,网上的资料虽多但很杂,笔者花了一天的时间对Solr进行了较为初步的研究,对Solr的基础应用做了一定的总结.文中涉及到的配置方法并不唯一,AP ...

  6. iOS 制作发布证书,发布到App Store

    ---恢复内容开始--- 1.登陆 iOS Dev Center 选择进入iOS Provisioning Portal. 2.在 iOS Provisioning Portal中,点击App IDs ...

  7. C语言链表全操作(增,删,改,查,逆序,递增排序,递减排序,链式队列,链式栈)

    一,数据结构——链表全操作: 链表形式: 其中,每个节点(Node)是一个结构体,这个结构体包含数据域,指针域,数据域用来存放数据,指针域则用来指向下一个节点: 特别说明:对于单链表,每个节点(Nod ...

  8. Map集合中的一些具体方法的体现

    package com.java.b.map.www; import java.util.Collection;import java.util.HashMap;import java.util.It ...

  9. 01_JavaMail_02_Base64加密

    [简述] Base64是网络上最常见的用于传输8Bit字节代码的编码方式之一.Base64编码可用于在HTTP环境下传递较长的标识信息.例如,在Java Persistence系统Hibernate中 ...

  10. RIME输入法

    RIME输入法 1.可以输入汉语拼音. (1) RIME内置的「地球拼音」可以在选择完字之后按下「Shift+Enter」键,直接输入汉语拼音,并且是带声调的. (2) 自己配置汉语拼音方案. 2.五 ...