DECLARE_DYNCREATE(DECLARE_DYNAMIC)与IMPLEMENT_DYNCREATE(IMPLEMENT_DYNAMIC)解析

        随便搜索一下,发现给出的解释是在运行期让派生类支持动态创建,可是给出详细解释的却很少,那么下面仔细看看此宏的扩展:

#define DECLARE_DYNCREATE(class_name) \
        DECLARE_DYNAMIC(class_name) \
        static CObject* PASCAL CreateObject();

#define _DECLARE_DYNCREATE(class_name) \
        _DECLARE_DYNAMIC(class_name) \
        static CObject* PASCAL CreateObject();

        从上面看到 DECLARE_DYNCREATE 内部使用了 DECLARE_DYNAMIC 宏,那么设想一下是否 IMPLEMENT_DYNCREATE 内部也应该使用 IMPLEMENT_DYNAMIC宏,我们来看看是不是这样:

#define IMPLEMENT_DYNCREATE(class_name, base_class_name) \
        CObject* PASCAL class_name::CreateObject() \
                { return new class_name; } \
        IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, 0xFFFF, \
                class_name::CreateObject, NULL)

        发现并没有 IMPLEMENT_DYNAMIC 宏,别着急,让我们先来看看 IMPLEMENT_DYNAMIC 宏:
#define IMPLEMENT_DYNAMIC(class_name, base_class_name) \
        IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, 0xFFFF, NULL, NULL)


        这样看来他们在内部是相同的,内部是使用 DECLARE_DYNAMIC 、IMPLEMENT_DYNAMIC,下面借来仔细观察这两个宏的内部拓展。


        IMPLEMENT_DYNAMIC 是实现“运行时类型识别”宏,与之相对应的是 DECLARE_DYNAMIC 声明“运行时类型识别”宏)。也就是说你在.CPP文件中如果看见有IMPLEMENT_DYNAMIC,则在.h文件中必定有DECLARE_DYNAMIC的声明。

        DECLARE_DYNAMIC/DECLARE_DYNAMIC 是为了确定运行时对象属于哪一个类而定义的宏。

        DECLARE_DYNCREATE/IMPLEMENT_DYNCREATE 是为了“动态创建"类的实例而定义的宏。new可以用来创建对象,但不能在还不知道要创建那个类的对象时进行动态的创建。可以参考一个很普遍的例子:

要在程序中实现根据拥护输入的类名来创建类的实例,下面的做法是通不过的

char szClassName[60];
cin >> szClassName;
CObject* pOb=new szClassName; //通不过

       这里就要用到 DEClARE_DYNCREATE/IMPLEMENT_DYNCREATE 定义的功能了。

查看afx.h头文件里的宏定义:

#ifdef _AFXDLL
#define DECLARE_DYNAMIC(class_name) \
protected: \
	static CRuntimeClass* PASCAL _GetBaseClass(); \
public: \
	static const CRuntimeClass class##class_name; \
	static CRuntimeClass* PASCAL GetThisClass(); \
	virtual CRuntimeClass* GetRuntimeClass() const; \

#define _DECLARE_DYNAMIC(class_name) \
protected: \
	static CRuntimeClass* PASCAL _GetBaseClass(); \
public: \
	static CRuntimeClass class##class_name; \
	static CRuntimeClass* PASCAL GetThisClass(); \
	virtual CRuntimeClass* GetRuntimeClass() const; \

#else
#define DECLARE_DYNAMIC(class_name) \
public: \
	static const CRuntimeClass class##class_name; \
	virtual CRuntimeClass* GetRuntimeClass() const; \

#define _DECLARE_DYNAMIC(class_name) \
public: \
	static CRuntimeClass class##class_name; \
	virtual CRuntimeClass* GetRuntimeClass() const; \

#endif

        让我们来逐行分析一下,首先来看“static CRuntimeClass class##class_name;”这个语句,其声明一个类型为CRuntimeClass的静态public成员变量,变量名是由字符串"class"与所指定的类的类名组成。

        举例而言,如果你写DECLARE_DYNAMIC(CMyView),则等于声明了一个静态变量

static CRuntimeClass classCMyView
        然后是“virtual CRuntimeClass* GetRuntimeClass() const;”语句,其声明一个虚函数,函数名为GetRuntimeClass,返回值为CRuntimeClass类型的指针,无形参,并且是个const函数。


#ifdef _AFXDLL
#define IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, wSchema, pfnNew, class_init) \
	CRuntimeClass* PASCAL class_name::_GetBaseClass() \
		{ return RUNTIME_CLASS(base_class_name); } \
	AFX_COMDAT const CRuntimeClass class_name::class##class_name = { \
		#class_name, sizeof(class class_name), wSchema, pfnNew, \
			&class_name::_GetBaseClass, NULL, class_init }; \
	CRuntimeClass* PASCAL class_name::GetThisClass() \
		{ return _RUNTIME_CLASS(class_name); } \
	CRuntimeClass* class_name::GetRuntimeClass() const \
		{ return _RUNTIME_CLASS(class_name); }

#define _IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, wSchema, pfnNew, class_init) \
	CRuntimeClass* PASCAL class_name::_GetBaseClass() \
		{ return RUNTIME_CLASS(base_class_name); } \
	AFX_COMDAT CRuntimeClass class_name::class##class_name = { \
		#class_name, sizeof(class class_name), wSchema, pfnNew, \
			&class_name::_GetBaseClass, NULL, class_init }; \
	CRuntimeClass* PASCAL class_name::GetThisClass() \
		{ return _RUNTIME_CLASS(class_name); } \
	CRuntimeClass* class_name::GetRuntimeClass() const \
		{ return _RUNTIME_CLASS(class_name); }

#else
#define IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, wSchema, pfnNew, class_init) \
	AFX_COMDAT const CRuntimeClass class_name::class##class_name = { \
		#class_name, sizeof(class class_name), wSchema, pfnNew, \
			RUNTIME_CLASS(base_class_name), NULL, class_init }; \
	CRuntimeClass* class_name::GetRuntimeClass() const \
		{ return RUNTIME_CLASS(class_name); }

#define _IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, wSchema, pfnNew, class_init) \
	AFX_COMDAT CRuntimeClass class_name::class##class_name = { \
		#class_name, sizeof(class class_name), wSchema, pfnNew, \
			RUNTIME_CLASS(base_class_name), NULL, class_init }; \
	CRuntimeClass* class_name::GetRuntimeClass() const \
		{ return RUNTIME_CLASS(class_name); }

#endif

        首先来看“AFX_COMDAT const CRuntimeClass class_name::class##class_name = {#class_name, sizeof(class class_name), wSchema, pfnNew, &class_name::_GetBaseClass, NULL, class_init }; ”语句,给之前在DECLARE_DYNAMIC里定义的CRuntimeClass类型的静态成员变量赋值。

        “CRuntimeClass* class_name::GetRuntimeClass() const { return _RUNTIME_CLASS(class_name); }”语句很简单,就一个return语句,是之前在DECLARE_DYNAMIC里定义的GetRuntimeClass的实现。下面再来看看其中嵌套使用的 RUNTIME_CLASS 宏定义:

#define _RUNTIME_CLASS(class_name) ((CRuntimeClass*)(&class_name::class##class_name))
#ifdef _AFXDLL
#define RUNTIME_CLASS(class_name) (class_name::GetThisClass())
#else
#define RUNTIME_CLASS(class_name) _RUNTIME_CLASS(class_name)
#endif

        这部分之所以单独define出一个宏,主要是为了方便从某个指定的class直接得到它的CRuntimeclass静态成员。

        最后来看CRuntimeClass,CRuntimeClass没有基类。每个由CObject派生的类都与一个CRuntimeClass结构相联系,用户可以使用该结构获取一个对象及其基类的运行时信息。当需要额外的函数参数检查时,或当用户必须根据一个对象的类编写特殊目的代码时,在运行时确定该对象的类就非常有用。C++并不直接支持运行时类的信息。

        在MFC中CObject::IsKindOf( const CRuntimeClass* pClass ) 利用CRuntimeClass来进行判定,如果你生成的类是以CObject为基础的,你可以使用该成员函数来判定。下面举一个参考来的例子来加深了解CRuntimeClass,以及那几个宏的作用。

class CAge : public CObject
{
        DECLARE_DYNCREATE(CAge);
};
class CAge2 : public CObject
{
        DECLARE_DYNCREATE(CAge2);
};

IMPLEMENT_DYNCREATE(CAge,CObject)
IMPLEMENT_DYNCREATE(CAge2,CObject)

BOOL IsAge(CObject* pO)
{
        return pO->IsKindOf( RUNTIME_CLASS( CAge ) );
};
BOOL IsAge2(CAge* pO)
{
        return pO->IsKindOf( RUNTIME_CLASS( CAge ) );
};

int main(int argc, char* argv[])
{
        
        CAge age;
        CAge2 age2;
        BOOL bKind = IsAge(&age2);//return FALSE
        bKind = IsAge(&age);//return TRUE
        bKind = IsAge2((CAge*)&age2);//return FALSE,避免强制转换带来的错误
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值