上回提要:在我们实现了我们的类型识别,不过在这里,光输出还不够,我们还需要一个类型比较的方法:实现起来也是极其简单的
BOOL CObject::IsKindOf(const CRuntimeClass* pClass) const
{
CRuntimeClass* pClassThis = GetRuntimeClass();
while (pClassThis != NULL)
{
if (pClassThis == pClass)
return TRUE;
pClassThis = pClassThis->m_pBaseClass;
}
return FALSE;
}
直接通过该方法获取对应类中的类型识别单元,然后递归向下的比较,以此来判断是否为某一类型~~~,简直不要更加简单
在我们拥有了对于一个类型的识别的功能之后,现在就该考虑另一个问题了:如何在程序执行期间根据动态获得一个类的名称来动态创建一个对应的类的对象,其实学习了这么长时间的设计模式之后,我曾经想过直接通过模板和工厂模式也都是可以很简单那实现的,不过这个都已经不是重点了,这里我们就来看看MFC中的动态创建的实现:
其实废话了那么久。MFC中的实现方式也是很简单,就是在类型识别单元中加入了提供对应对象构造函数的方法,(其实其他的那几种写法说到底不也是这么玩的么?)
具体的操作如下:
struct CRuntimeClass
{
//属性
LPCSTR m_lpszClassName;
int m_nObjectSize;
UINT m_wSchema;
CObject* (PASCAL* m_pfnCreateObject)(); //NULL => abstract class
CRuntimeClass* m_pBaseClass;
CObject* CreateObject();
static CRuntimeClass* PASCAL Load();
//运行时类型的对象会被链接到一条链表上
static CRuntimeClass* pFirstClass; //型录的起点
CRuntimeClass* m_pNextClass; //被链接到一条型录上
};
添加了中间部分的2个成员,其作用分别为一个是型录提供动态创建的方法,另一个则是判断是否具有动态创建能力的方法,在这里顺便补充一句,之前一直不明所以的函数指针m_pfnCreateObject在这里也展示了他的作用,用来传递动态创建的方法
他们的实现部分如下:
//CreateObject()
CObject* CRuntimeClass::CreateObject()
{
if (m_pfnCreateObject == NULL)
{
TRACEL("Error: Trying to create object which is not "
"DECLARE_DYNCREATE \nor DECLARE_SERIAL: %hs.\n", m_lpszClassName);
return NULL;
}
CObject* pObject = NULL;
pObject = (*m_pfnCreateObject)();
return pObject;
}
//Load()
CRuntimeClass* PASCAL CRuntimeClass::Load()
{
char szClassName[64];
CRuntimeClass* pClass;
cout << "enter a class name...";
cin >> szClassName;
for (pClass = pFirstClass; pClass != NULL; pClass = pClass->m_pNextClass)
{
if (strcmp(szClassName, pClass->m_lpszClassName) == 0)
return pClass;
}
TRACEL("Error: Class not found: %s \n",szClassName);
return NULL;
}
//m_pfnCreateObject
#define IMPLEMENT_DYNCREATE(class_name , base_class_name) \
CObject* PASCAL class_name::CreateObject() \
{ return new class_name ;} \
_IMPLEMENT_RUNNTIMECLASS(class_name , base_class_name , 0xFFFF , \
class_name::CreateObject)
这里还忘了了说了,由于每个考虑到对象的繁多,每个类型的都应当有对应的构造的方法的提供,然后统一交由型录对象来处理,
实现代码如下:
#define DECLARE_DYNAMIC(class_name) \
public: \
static CRuntimeClass class##class_name; \
virtual CRuntimeClass* GetRuntimeClass() const;
CObject* PASCAL class_name::CreateObject() \
{ return new class_name ;} \
有了这些之后,我们的类库之中的类就便具有动态创建的能力。。。。。
最后附上侯俊杰先生的完整样例代码:
//MFC.h
#pragma once
#define BOOL int
#define TRUE 1
#define FALSE 0
#define LPCSTR LPSTR
typedef char* LPSTR;
#define UINT int
#define PASCAL _stdcall
#define TRACEL printf
#include
#include
#include
#include
using namespace std;
class CObject;
struct CRuntimeClass
{
//属性
LPCSTR m_lpszClassName;
int m_nObjectSize;
UINT m_wSchema;
CObject* (PASCAL* m_pfnCreateObject)(); //NULL => abstract class
CRuntimeClass* m_pBaseClass;
CObject* CreateObject();
static CRuntimeClass* PASCAL Load();
//运行时类型的对象会被链接到一条链表上
static CRuntimeClass* pFirstClass; //型录的起点
CRuntimeClass* m_pNextClass; //被链接到一条型录上
};
struct AFX_CLASSINIT {
AFX_CLASSINIT(CRuntimeClass* pNewClass);
};
#define RUNTIME_CLASS(class_name) \
(&class_name::class##class_name)
#define DECLARE_DYNAMIC(class_name) \
public: \
static CRuntimeClass class##class_name; \
virtual CRuntimeClass* GetRuntimeClass() const;
#define DECLARE_DYNCREATE(class_name) \
DECLARE_DYNAMIC(class_name) \
static CObject* PASCAL CreateObject();
#define _IMPLEMENT_RUNNTIMECLASS(class_name , base_class_name , wSchema , pfnNew) \
static char _lpsz##class_name[] = #class_name; \
CRuntimeClass class_name::class##class_name = { \
_lpsz##class_name , sizeof(class_name) , wSchema ,pfnNew , \
RUNTIME_CLASS(base_class_name),NULL}; \
static AFX_CLASSINIT _init_##class_name(&class_name::class##class_name); \
CRuntimeClass* class_name::GetRuntimeClass() const \
{ return &class_name::class##class_name; } \
#define IMPLEMENT_DYNAMIC(class_name ,base_class_name) \
_IMPLEMENT_RUNNTIMECLASS(class_name ,base_class_name , 0xFFFF,NULL)
#define IMPLEMENT_DYNCREATE(class_name , base_class_name) \
CObject* PASCAL class_name::CreateObject() \
{ return new class_name ;} \
_IMPLEMENT_RUNNTIMECLASS(class_name , base_class_name , 0xFFFF , \
class_name::CreateObject)
class CObject
{
public:
CObject::CObject() {}
CObject::~CObject() {}
virtual CRuntimeClass* GetRuntimeClass() const;
BOOL IsKindOf(const CRuntimeClass* pClass) const;
public:
static CRuntimeClass classCObject;
virtual void SayHello() { cout << "Hello CObject \n"; }
};
class CCmdTarget : public CObject
{
DECLARE_DYNAMIC(CCmdTarget)
public:
CCmdTarget::CCmdTarget() {}
CCmdTarget::~CCmdTarget() {}
};
class CWinThread :public CCmdTarget
{
DECLARE_DYNAMIC(CWinThread)
public:
CWinThread::CWinThread() {}
CWinThread::~CWinThread() {}
virtual BOOL InitInstance() {
return TRUE;
}
virtual int Run() {
return 1;
}
};
class CWnd;
class CWinApp :public CWinThread
{
DECLARE_DYNAMIC(CWinApp)
public:
CWinApp* m_pCurrentWinApp;
CWnd* m_pMainWnd;
public:
CWinApp::CWinApp() {
m_pCurrentWinApp = this;
}
CWinApp::~CWinApp() {}
virtual BOOL InitApplication() {
return TRUE;
}
virtual BOOL InitInstance() {
return TRUE;
}
virtual int Run() {
return CWinThread::Run();
}
};
class CDoocument : public CCmdTarget
{
DECLARE_DYNAMIC(CDoocument)
public:
CDoocument::CDoocument() {
}
CDoocument::~CDoocument() {
}
};
class CWnd :public CCmdTarget
{
DECLARE_DYNCREATE(CWnd)
public:
CWnd::CWnd() {
cout << "CWnd Constructor" << endl;
}
CWnd::~CWnd() {}
virtual BOOL Create();
BOOL CreateEx();
virtual BOOL PreCreateWindow();
void SayHello() {
cout << "Hello CWnd \n" << endl;
}
};
class CFrameWnd :public CWnd
{
DECLARE_DYNCREATE(CFrameWnd)
public:
CFrameWnd::CFrameWnd() {
cout << "CFrameWnd Constructor" << endl;
}
CFrameWnd::~CFrameWnd() {
}
BOOL Create();
virtual BOOL PreCreateWindow();
void SayHello() {
cout << "Hello CFrameWnd"<
//MFC.cpp
#include"MY.h"
extern CMyWinApp theApp;
static char szCObject[] = "CObject";
struct CRuntimeClass CObject::classCObject =
{ szCObject ,sizeof(CObject) , 0xffff , NULL ,NULL ,NULL };
static AFX_CLASSINIT _init_CObject(&CObject::classCObject);
CRuntimeClass* CRuntimeClass::pFirstClass = NULL;
AFX_CLASSINIT::AFX_CLASSINIT(CRuntimeClass* pNewClass)
{
pNewClass->m_pNextClass = CRuntimeClass::pFirstClass;
CRuntimeClass::pFirstClass = pNewClass;
}
CObject* CRuntimeClass::CreateObject()
{
if (m_pfnCreateObject == NULL)
{
TRACEL("Error: Trying to create object which is not "
"DECLARE_DYNCREATE \nor DECLARE_SERIAL: %hs.\n", m_lpszClassName);
return NULL;
}
CObject* pObject = NULL;
pObject = (*m_pfnCreateObject)();
return pObject;
}
CRuntimeClass* PASCAL CRuntimeClass::Load()
{
char szClassName[64];
CRuntimeClass* pClass;
cout << "enter a class name...";
cin >> szClassName;
for (pClass = pFirstClass; pClass != NULL; pClass = pClass->m_pNextClass)
{
if (strcmp(szClassName, pClass->m_lpszClassName) == 0)
return pClass;
}
TRACEL("Error: Class not found: %s \n",szClassName);
return NULL;
}
CRuntimeClass* CObject::GetRuntimeClass() const
{
return &CObject::classCObject;
}
BOOL CObject::IsKindOf(const CRuntimeClass* pClass) const
{
CRuntimeClass* pClassThis = GetRuntimeClass();
while (pClassThis != NULL)
{
if (pClassThis == pClass)
return TRUE;
pClassThis = pClassThis->m_pBaseClass;
}
return FALSE;
}
BOOL CWnd::Create()
{
return TRUE;
}
BOOL CWnd::CreateEx()
{
PreCreateWindow();
return TRUE;
}
BOOL CWnd::PreCreateWindow()
{
return TRUE;
}
BOOL CFrameWnd::Create()
{
CreateEx();
return TRUE;
}
BOOL CFrameWnd::PreCreateWindow()
{
return TRUE;
}
CWinApp* AfxGetApp()
{
return theApp.m_pCurrentWinApp;
}
IMPLEMENT_DYNAMIC(CCmdTarget , CObject)
IMPLEMENT_DYNAMIC(CWinThread , CCmdTarget)
IMPLEMENT_DYNAMIC(CWinApp , CWinThread)
IMPLEMENT_DYNAMIC(CDoocument , CCmdTarget)
IMPLEMENT_DYNCREATE(CWnd , CCmdTarget)
IMPLEMENT_DYNAMIC(CView ,CWnd)
IMPLEMENT_DYNCREATE(CFrameWnd , CWnd)
//MY.h
#pragma once
#include
#include"MFC.h"
using namespace std;
class CMyWinApp :public CWinApp
{
public:
CMyWinApp::CMyWinApp() {}
CMyWinApp::~CMyWinApp() {}
virtual BOOL InitInstance();
};
class CMyFrameWnd : public CFrameWnd
{
DECLARE_DYNCREATE(CMyFrameWnd)
public:
CMyFrameWnd();
~CMyFrameWnd() {}
void SayHello() {
cout << "Hello CMyFrameWnd"<
//MY.cpp
#include"MY.h"
using namespace std;
CMyWinApp theApp;
BOOL CMyWinApp::InitInstance()
{
m_pMainWnd = new CMyFrameWnd;
return TRUE;
}
CMyFrameWnd::CMyFrameWnd()
{
cout << "CMyFrameWnd Constructor" << endl;
Create();
}
IMPLEMENT_DYNCREATE(CMyFrameWnd, CFrameWnd)
IMPLEMENT_DYNCREATE(CMyDoc,CDoocument)
IMPLEMENT_DYNCREATE(CMyView,CView)
void PrintAllClasses()
{
CRuntimeClass* pClass;
for (pClass = CRuntimeClass::pFirstClass;
pClass != NULL;
pClass = pClass->m_pNextClass)
{
cout << pClass->m_lpszClassName << endl;
cout << pClass->m_nObjectSize << endl;
cout << pClass->m_wSchema << endl;
}
}
void main()
{
CWinApp* pApp = AfxGetApp();
pApp->InitApplication();
pApp->InitInstance();
pApp->Run();
CRuntimeClass* pClassRef;
CObject* pOb;
while (1)
{
if ((pClassRef = CRuntimeClass::Load()) == NULL)
break;
pOb = pClassRef->CreateObject();
if (pOb != NULL)
{
pOb->SayHello();
}
}
}