随便搜索一下,发现给出的解释是在运行期让派生类支持动态创建,可是给出详细解释的却很少,那么下面仔细看看此宏的扩展:
#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)
#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; //通不过
查看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
举例而言,如果你写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
“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
最后来看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,避免强制转换带来的错误
}