按照Frame3中的图(3-1)“类别型录”网,要实现 IsKindOf功能,再轻松不过了。
1)为CObject 加上一个 IsKindOf 函数,于是此函数将被所有类继承。它将把参数所指定的某个 CRuntimeClass对象拿来与类别型录中的元素一一比较。如果比较成功(即在类别型录里有存在),就传回TRUE;否则,传回FALSE。
// in header file
class CObject
{
public:
...
BOOL IsKindOf(const CRuntimeClass* pClass) const;
};
//in implementation file
BOOL CObject::IsKindOf(const CRuntimeClass* pClass) const //类型识别
{
CRuntimeClass* pClassThis = GetRuntimeClass();
while (pClassThis!=NULL)
{
if (pClassThis == pClass)
{
return TRUE;
}
pClassThis = pClassThis->m_pBaseClass;
}
return FALSE;
}
注意,while循环中所追踪的是“同宗”路线,也就是凭借着 m_pBaseClass而非m_pNextClass。假设我们调用的是:
CView* pView = new CView;
pView->IsKingOf(RUNTIME_CLASS(CWINAPP));
IsKindOf 的参数其实就是 &CWinApp::classCWinApp。函数内利用GetRuntimeClass先取得 &CView::classCView,然后循线而上(从图3-1来看,所谓的循线分别是CView、CWnd、CCmdTarget、CObject),每获得一个 CRuntimeClass对象指针,就拿来和 CView::classCView的指针比较。依照此思路,就完成了 IsKindOf函数。
2)IsKindOf的使用方式如下:
CMyDoc* pMyDoc = new CMyDoc;
CMyView* pMyView = new CMyView;
CWnd* pMyWnd = pApp->m_pMainWnd;
cout<<pMyDoc->IsKindOf(RUNTIME_CLASS(CMyDoc))<<"\n"; //为true
cout<<pMyDoc->IsKindOf(RUNTIME_CLASS(CDocument))<<"\n"; //为true
cout<<pMyDoc->IsKindOf(RUNTIME_CLASS(CCmdTarget))<<"\n"; //为true
cout<<pMyDoc->IsKindOf(RUNTIME_CLASS(CObject))<<"\n"; //为true
cout<<pMyDoc->IsKindOf(RUNTIME_CLASS(CWinApp))<<"\n"; //为false
cout<<pMyDoc->IsKindOf(RUNTIME_CLASS(CView))<<"\n\n"; //为false
cout<<pMyView->IsKindOf(RUNTIME_CLASS(CView))<<"\n"; //为true
cout<<pMyView->IsKindOf(RUNTIME_CLASS(CObject))<<"\n"; //为true
cout<<pMyView->IsKindOf(RUNTIME_CLASS(CWnd))<<"\n"; //为true
cout<<pMyView->IsKindOf(RUNTIME_CLASS(CFrameWnd))<<"\n\n"; //为false
cout<<pMyWnd->IsKindOf(RUNTIME_CLASS(CFrameWnd))<<"\n"; //为true
cout<<pMyWnd->IsKindOf(RUNTIME_CLASS(CWnd))<<"\n"; //为true
cout<<pMyWnd->IsKindOf(RUNTIME_CLASS(CObject))<<"\n"; //为true
cout<<"pMyWnd->IsKindOf(RUNTIME_CLASS(CDocument))<<"\n"; //为false
详细代码,请看工程Frame4。
效果如下:
图(2)“类型识别”的结果
//mfc.h
#define BOOL int
#define TRUE 1
#define FALSE 0
#define LPCSTR LPSTR
typedef char* LPSTR;
#define UINT int
#define PASCAL _stdcall
#include <iostream.h>
class CObject;
struct CRuntimeClass
{
// Attributes
LPCSTR m_lpszClassName;
int m_nObjectSize;
UINT m_wSchema; // schema number of the loaded class
CObject* (PASCAL* m_pfnCreateObject)(); // NULL => abstract class
CRuntimeClass* m_pBaseClass;
// CRuntimeClass objects linked together in simple list
static CRuntimeClass* pFirstClass; // start of class list
CRuntimeClass* m_pNextClass; // linked list of registered classes
};
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 _IMPLEMENT_RUNTIMECLASS(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_RUNTIMECLASS(class_name, base_class_name, 0xFFFF, NULL)
class CObject
{
public:
CObject::CObject() {
}
CObject::~CObject() {
}
virtual CRuntimeClass* GetRuntimeClass() const;
BOOL IsKindOf(const CRuntimeClass* pClass) const;
public:
static CRuntimeClass classCObject;
};
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 CDocument : public CCmdTarget
{
DECLARE_DYNAMIC(CDocument)
public:
CDocument::CDocument() {
}
CDocument::~CDocument() {
}
};
class CWnd : public CCmdTarget
{
DECLARE_DYNAMIC(CWnd)
public:
CWnd::CWnd() {
}
CWnd::~CWnd() {
}
virtual BOOL Create();
BOOL CreateEx();
virtual BOOL PreCreateWindow();
};
class CFrameWnd : public CWnd
{
DECLARE_DYNAMIC(CFrameWnd)
public:
CFrameWnd::CFrameWnd() {
}
CFrameWnd::~CFrameWnd() {
}
BOOL Create();
virtual BOOL PreCreateWindow();
};
class CView : public CWnd
{
DECLARE_DYNAMIC(CView)
public:
CView::CView() {
}
CView::~CView() {
}
};
// global function
CWinApp* AfxGetApp();
//mfc.cpp
#include "my.h"
extern CMyWinApp theApp;
static char szCObject[] = "CObject";
struct CRuntimeClass CObject::classCObject =
{ szCObject,sizeof(CObject),0xffff,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;
}
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;
}
IMPLEMENT_DYNAMIC(CCmdTarget,CObject)
IMPLEMENT_DYNAMIC(CWinThread,CCmdTarget)
IMPLEMENT_DYNAMIC(CWinApp,CWinThread)
IMPLEMENT_DYNAMIC(CWnd,CCmdTarget) //其实在MFC中此句是,IMPLEMENT_DYNCREATE()
IMPLEMENT_DYNAMIC(CFrameWnd,CWnd) //其实在MFC中此句是,IMPLEMENT_DYNCREATE()
IMPLEMENT_DYNAMIC(CDocument,CCmdTarget)
IMPLEMENT_DYNAMIC(CView,CWnd)
//global function
CWinApp* AfxGetApp()
{
return theApp.m_pCurrentWinApp;
}
//my.h
#include <iostream.h>
#include "mfc.h"
class CMyWinApp:public CWinApp
{
public:
CMyWinApp::CMyWinApp(){}
CMyWinApp::~CMyWinApp(){}
virtual BOOL InitInstance();
};
class CMyFrameWnd:public CFrameWnd
{
DECLARE_DYNAMIC(CMyFrameWnd)
public:
CMyFrameWnd();
~CMyFrameWnd(){}
};
class CMyDoc:public CDocument
{
DECLARE_DYNAMIC(CMyDoc)
public:
CMyDoc::CMyDoc(){}
CMyDoc::~CMyDoc(){}
};
class CMyView:public CView
{
DECLARE_DYNAMIC(CMyView)
public:
CMyView::CMyView(){}
CMyView::~CMyView(){}
};
//global function
void PrintAllClasses();
//my.cpp
#include "my.h"
CMyWinApp theApp;
BOOL CMyWinApp::InitInstance()
{
m_pMainWnd = new CMyFrameWnd;
return TRUE;
}
CMyFrameWnd::CMyFrameWnd()
{
Create();
}
//宏的实现
IMPLEMENT_DYNAMIC(CMyFrameWnd,CFrameWnd) //在MFC中,此语句是,IMPLEMENT_DYNCREATE(CMyFrameWnd,CFrameWnd)
IMPLEMENT_DYNAMIC(CMyDoc,CDocument) //在MFC中,此语句是,IMPLEMENT_DYNCREATE(CMyDoc,CDocument)
IMPLEMENT_DYNAMIC(CMyView,CView) //在MFC中,此语句是,IMPLEMENT_DYNCREATE(CMyView,CView)
void PrintAllClasses() //输出“类别型录网“
{
CRuntimeClass* pClass;
//just walk through the simple list of registered classes
for(pClass = CRuntimeClass::pFirstClass; pClass!=NULL;
pClass = pClass->m_pNextClass)
{
cout<<pClass->m_lpszClassName<<"\n";
cout<<pClass->m_nObjectSize<<"\n";
cout<<pClass->m_wSchema<<"\n";
}
}
void main()
{
CWinApp* pApp = AfxGetApp();
pApp->InitApplication();
pApp->InitInstance();
pApp->Run();
//PrintAllClasses();
CMyDoc* pMyDoc = new CMyDoc;
CMyView* pMyView = new CMyView;
CWnd* pMyWnd = pApp->m_pMainWnd;
cout<<"pMyDoc->IsKindOf(RUNTIME_CLASS(CMyDoc)) "<<pMyDoc->IsKindOf(RUNTIME_CLASS(CMyDoc))<<"\n";
cout<<"pMyDoc->IsKindOf(RUNTIME_CLASS(CDocument)) "<<pMyDoc->IsKindOf(RUNTIME_CLASS(CDocument))<<"\n";
cout<<"pMyDoc->IsKindOf(RUNTIME_CLASS(CCmdTarget)) "<<pMyDoc->IsKindOf(RUNTIME_CLASS(CCmdTarget))<<"\n";
cout<<"pMyDoc->IsKindOf(RUNTIME_CLASS(CObject)) "<<pMyDoc->IsKindOf(RUNTIME_CLASS(CObject))<<"\n";
cout<<"pMyDoc->IsKindOf(RUNTIME_CLASS(CWinApp)) "<<pMyDoc->IsKindOf(RUNTIME_CLASS(CWinApp))<<"\n";
cout<<"pMyDoc->IsKindOf(RUNTIME_CLASS(CView)) "<<pMyDoc->IsKindOf(RUNTIME_CLASS(CView))<<"\n\n";
cout<<"pMyView->IsKindOf(RUNTIME_CLASS(CView)) "<<pMyView->IsKindOf(RUNTIME_CLASS(CView))<<"\n";
cout<<"pMyView->IsKindOf(RUNTIME_CLASS(CObject)) "<<pMyView->IsKindOf(RUNTIME_CLASS(CObject))<<"\n";
cout<<"pMyView->IsKindOf(RUNTIME_CLASS(CWnd)) "<<pMyView->IsKindOf(RUNTIME_CLASS(CWnd))<<"\n";
cout<<"pMyView->IsKindOf(RUNTIME_CLASS(CFrameWnd)) "<<pMyView->IsKindOf(RUNTIME_CLASS(CFrameWnd))<<"\n\n";
cout<<"pMyWnd->IsKindOf(RUNTIME_CLASS(CFrameWnd)) "<<pMyWnd->IsKindOf(RUNTIME_CLASS(CFrameWnd))<<"\n";
cout<<"pMyWnd->IsKindOf(RUNTIME_CLASS(CWnd)) "<<pMyWnd->IsKindOf(RUNTIME_CLASS(CWnd))<<"\n";
cout<<"pMyWnd->IsKindOf(RUNTIME_CLASS(CObject)) "<<pMyWnd->IsKindOf(RUNTIME_CLASS(CObject))<<"\n";
cout<<"pMyWnd->IsKindOf(RUNTIME_CLASS(CDocument)) "<<pMyWnd->IsKindOf(RUNTIME_CLASS(CDocument))<<"\n";
}