DECLARE_DYNCREATE(DECLARE_DYNAMIC)与IMPLEMENT_DYNCREATE(IMPLEMENT_DYNAMIC)解析「建议收藏」

DECLARE_DYNCREATE(DECLARE_DYNAMIC)与IMPLEMENT_DYNCREATE(IMPLEMENT_DYNAMIC)解析「建议收藏」随便搜索一下,发现给出的解释是在运行期让派生类支持动态创建,可是给出详细解释的却很少,那么下面仔细看看此宏的扩展:#defineDECLARE_DYNCREATE(class_name)\DECLARE_DYNAMIC(class_name)\staticCObject*PASCALCreateObject();#define_DECLAR

大家好,欢迎来到IT知识分享网。

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

#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,避免强制转换带来的错误 }

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/26346.html

(0)

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信