更多 C++ 习语/通过初始化附加
在程序执行开始之前将用户定义的对象附加到框架。
- 带有构造函数的静态对象
某些应用程序编程框架,如 GUI 框架(例如 Microsoft MFC)和对象请求代理(例如某些 CORBA 实现)使用自己的内部消息循环(也称为事件循环)来控制整个应用程序。应用程序程序员可能或可能没有自由编写应用程序级 main
函数。通常,main
函数被埋藏在应用程序框架的深处(例如,MFC 中的 AfxWinMain
)。无法访问 main
使程序员无法在主事件循环开始之前编写应用程序特定的初始化代码。通过初始化附加习语是一种在框架控制的循环开始执行之前执行应用程序特定代码的方法。
在 C++ 中,全局对象和全局命名空间中的静态对象在 main
开始之前初始化。这些对象也称为静态存储持续时间的对象。静态存储持续时间的对象的这一属性可用于将对象附加到系统,如果程序员不允许编写自己的 main
函数。例如,考虑以下使用 Microsoft Foundation Classes (MFC) 的(最小可能)示例
///// File = Hello.h
class HelloApp: public CWinApp
{
public:
virtual BOOL InitInstance ();
};
///// File = Hello.cpp
#include <afxwin.h>
#include "Hello.h"
HelloApp myApp; // Global "application" object
BOOL HelloApp::InitInstance ()
{
m_pMainWnd = new CFrameWnd();
m_pMainWnd->Create(0,"Hello, World!!");
m_pMainWnd->ShowWindow(SW_SHOW);
return TRUE;
}
上面的示例创建了一个标题为“Hello, World!” 的窗口,仅此而已。这里要注意的关键是 HelloApp
类型的全局对象 myApp
。myApp
对象在 main
执行之前被默认初始化。作为初始化对象的副作用,CWinApp
的构造函数也被调用。CWinApp
类是框架的一部分,并调用框架中其他几个类的构造函数。在这些构造函数的执行过程中,全局对象被附加到框架。该对象后来被 AfxWinMain
检索,它是常规 main
的 MFC 等效项。HelloApp::InitInstance
成员函数仅为完整起见而显示,不是该习语的必要组成部分。此函数在 AfxWinMain
开始执行后调用。
全局和静态对象可以通过几种方式初始化:默认构造函数、带参数的构造函数、从函数的返回值赋值、动态初始化等。
注意事项
在 C++ 中,同一个编译单元中的对象按定义顺序创建。但是,跨不同编译单元的静态存储持续时间对象的初始化顺序没有明确定义。命名空间中的对象在访问该命名空间中的任何函数/变量之前创建。这可能或可能不在 main
之前。销毁顺序与初始化顺序相反,但初始化顺序本身没有标准化。由于这种未定义的行为,当静态对象的构造函数使用尚未初始化的另一个静态对象时,会发生静态初始化顺序问题。这种习语很容易陷入这个陷阱,因为它依赖于静态存储持续时间的对象。