VC++自动生成的对话框类头文件中的enum {IDD= xxxx}解释

1 MFC中对话框类和对话框资源之间的联系

使用VC++ MFC做开发的时候,经常需要插入对话框资源,然后根据这个资源生成相应的对话框类文件。类文件和对话框资源之间的联系纽带就是对话框控件ID,与其他资源ID一样,也是一个整数而已,只不过VC++开发环境在resource.h文件中增加了一个宏定义来描述这个整数而已。下面是一个对话框类的头文件。


#pragma once


// CTestDlg 对话框

class CTestDlg : public CDialog
{
	DECLARE_DYNAMIC(CTestDlg)

public:
	CTestDlg(CWnd* pParent = NULL);   // 标准构造函数
	virtual ~CTestDlg();

// 对话框数据
	enum { IDD = IDD_DIALOG1 };

protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持

	DECLARE_MESSAGE_MAP()
};

其中的  IDD_DIALOG1就是对应的对话框资源的ID,其宏定义可以在resource.h文件中找到,如下所示:

//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by TestStaticMemberFunction.rc
//
#define IDM_ABOUTBOX                    0x0010
#define IDD_ABOUTBOX                    100
#define IDS_ABOUTBOX                    101
#define IDD_TESTSTATICMEMBERFUNCTION_DIALOG 102
#define IDR_MAINFRAME                   128
#define IDD_DIALOG1                     129  // 在这里
#define IDC_BUTTON1                     1000

// Next default values for new objects
// 
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE        130
#define _APS_NEXT_COMMAND_VALUE         32771
#define _APS_NEXT_CONTROL_VALUE         1001
#define _APS_NEXT_SYMED_VALUE           101
#endif
#endif
当然,资源文件(.rc)里也必须使用这个IDD_DIALOG1对使用的对话框资源进行描述,如下所示:

/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//

IDD_ABOUTBOX DIALOGEX 0, 0, 170, 62
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "关于 TestStaticMemberFunction"
FONT 9, "MS Shell Dlg", 0, 0, 0x1
BEGIN
    ICON            IDR_MAINFRAME,IDC_STATIC,14,14,21,20
    LTEXT           "TestStaticMemberFunction,1.0 版",IDC_STATIC,42,14,114,8,SS_NOPREFIX
    LTEXT           "Copyright (C) 2014",IDC_STATIC,42,26,114,8
    DEFPUSHBUTTON   "确定",IDOK,113,41,50,14,WS_GROUP
END

IDD_TESTSTATICMEMBERFUNCTION_DIALOG DIALOGEX 0, 0, 395, 194
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
EXSTYLE WS_EX_APPWINDOW
CAPTION "TestStaticMemberFunction"
FONT 9, "MS Shell Dlg", 0, 0, 0x1
BEGIN
    PUSHBUTTON      "Button1",IDC_BUTTON1,72,37,50,14
END

IDD_DIALOG1 DIALOGEX 0, 0, 316, 182 // 在这里
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Dialog"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
    DEFPUSHBUTTON   "确定",IDOK,205,161,50,14
    PUSHBUTTON      "取消",IDCANCEL,259,161,50,14
END


我们知道,在Win32 API中创建一个对话框的函数中有一个必须的参数就是对话框资源ID,MFC是对Win32API的浅薄封装,当然也需要把这个资源ID。我们可以在对话框类的实现文件中看到这个资源ID被当作参数传递给了构造函数。如下所示:

CTestDlg::CTestDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CTestDlg::IDD, pParent) // 在这里
{

}

CTestDlg::~CTestDlg()
{
}

2 enum {IDD= xxxx} 用法的解释

按照一般的理解,我们只需要把对话框资源ID作为一个静态整数常量成员存放就可以了,如下所示:

	//enum { IDD = IDD_DIALOG1 };
	static const int IDD = IDD_DIALOG1;
事实证明,这样做确实没有问题,程序编译运行完全一样。

那么这个enum的用法到底是什么含义呢?如此用法,IDD会是静态常量吗?

这样从enum的语法说起,enum的常用方式为 enum 类型名 { 枚举子名1=1, 枚举子名2, ... };   此后就可以使用 类型名 声明变量了。如果把类型名去掉了,我们得到的是一个无名类型,这个类型也就无法使用,但是其中的枚举子由于具有独立的名字,所以仍然可以直接使用。枚举子的名字有个命名空间的问题,在C中,枚举子命名空间就是全局空间,而在C++中,除了专用的namespace关键字可以建立命名空间,类名本身也是一个命名空间,这样由于enum用到了对话框类的里面,所以其中枚举子的命名空间就是类名了。这样在类外部访问这个枚举子的时候就需要加类名,如 CTestDlg::IDD,当然如果在类的成员函数中进行访问,就没有必要加类名了。

通过分析可见,单从CTestDlg::IDD这个表达式,不能断定IDD到底是CTestDlg类的静态成员变量,因为它还可能是位于CTestDlg这个名字空间里面的枚举子常量,或者其他。

MFC之所以使用枚举子而不是静态成员变量,也许基于如下考虑:(1)语法更简洁,(2)编译器在编译时直接计算出枚举子的值,从而成了字面常量,效率更高。

可是微乳也许没想到,这种用法也给初学者造成了很多困惑。

3 学会在自己的项目中使用enum

其实enum这种用法在其他项目中也很常见,很多是为了替代宏定义,例如如下宏定义

#define MONDAY		1
#define TUESDAY		2
#define WEDNESDAY	3
#define THURSDAY	4
#define FRIDAY		5
#define SATURDAY	6
#define SUNDAY		7


完全可以使用如下枚举子来代替

enum
{
	MODAY = 1,
	TUESDAY = 2,
	WEDNESDAY = 3,
	THURSDAY = 4,
	FRIDAY = 5,
	SATURDAY = 6,
	SUNDAY = 7
}
大家都知道宏定义会潜在很多问题,而且对调试也不方便,所以多多使用enum吧!

VC++自动生成的对话框类头文件中的enum {IDD= xxxx}解释

上一篇:Effective C++ 解析 1


下一篇:Python 学习入门(36)—— @property属性