深入浅出MFC学习笔记:(第三章MFC六大关键技术之仿真:类型识别,动态创建) .

本文介绍MFC中动态类型识别(RTTI)和动态创建两大关键技术的实现原理。详细解析了CRuntimeClass结构及其在类继承体系中的作用,展示了如何通过宏定义实现类型识别与动态创建功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

第三章MFC六大关键技术之仿真:类型识别

   深入理解MFC的内部运行原理,是本次学习《深入浅出MFC》的主要目的。要模仿的六大技术包括:

1MFC程序的初始化过程。

2RTTIRuntime type identification)运行时类型识别。

3Dynamic creation 动态创建

4Persistence永久保存

5:消息映射

6:消息传递。

RTTI(运行时类型识别)

    IsKindOf能够侦测某个对象是否属于某种类。即判断某一对象所属的类是否是父类或当前类;

    要达到动态类型识别的能力,必须在构建类继承体系时记录必要的信息,这被称为类型型录表。MFC以链表的方式建立了此表。

    类型型录表的每个元素为CRuntimeClass类型,其定义为:

class CRuntimeClass

{

public:

   LPCSTR m_lpszClassName;//对象所属类名

   Int m_nObjectSize;//对象大小

   UINT m_wSchema;//模式号

   CObject *(PASCAL*m_pfnCreateObject)();//构建函数抽象类为NULL

   CRuntimeClass *pBaseClasss;//基类CRuntimeClass对象指针。

   Static CRuntimeClass *pFirstClass;//链表头指针。

   CRuntimeClass  *m_pNextClass;//下一指针。

};


 

MFC使用此类作为每个类的成员变量。使用宏定义为每个类定义了自己的CRuntimeClass成员变量。

DECLAR_DYNAMICIMPLENMENT_DYNAMIC

使用这两个宏将CRuntimeClass对象不知不觉放到类之中。

DECLARE_DYNMIC宏定义如下:

#define DELCARE_DYNMIC (  class_name   )   \

public:\

     static CRuntimeClass class##class_name  \

     virtual CRuntimeClass *GetRuntimeClass()const;


 

##用来告诉编译器把两个字符串连接起来。

如果使用这个宏:DELCARE_DYNMICCView);

那么预编译器将生成下列代码:

public:

static CRuntimeClass classCView;

virtual CRuntimeClass*GetRuntimeClass()const;



 

以上代码仅仅是在类中定义CRuntimeClass对象,并定义一个返回CRuntimeClass对象地址的函数。注意CRuntimeClassstatic的,也就是说同一种类继承体系的对象共享一个CRuntimeClass对象。

初始化对象的内容以及建立类型型录表需要使用IMPLEMENT_DYNMIC宏。

#define IMPLEMENT_DYNMIC (class_name,base_class_name)\

_IMPLEMENT_RUNTIMECLASS(class_name,base_class_name,0xFFFF,NULL); 

_IMPLEMENT_RUNTIMECLASS又是一个宏,它定义如下:

#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##classname;\

        }

#define RUNTIME_CLASS(class_name)\

   ( &class_name::class##class_name);


 

AFX_CLASSINIT是一个类,看着跟宏定义似的,这样做很容易让人迷惑。它用于将本节点连接到类型型录表,定义如下:

class AFX_CLASSINIT

{

  public:

     AFX_CLASSINIT(CRuntimeClass*pNewClass)//构造函数

     { 

       pNewClass->m_pNextClass=CRuntime::pFirstClass;

       CRuntimeClass::pFirstClass =pNewClass;

     }

};


 

用法:

class CWnd:public CCmdTarget

{

  public:

    DECLARE_DYNAMIC(CWnd);


};


 

IMPLEMENT_DYNMIC(CWnd,CCmdTarget);

代码展开后为;

class CWnd:public CCmdTarget

{

  public:

    static CRuntimeClass classCView;

    virtual CRuntimeClass*GetRuntimeClass()const

     

};



static char _lpszCWnd[]="CWnd";

CRuntimeClass CWnd::classCWnd=

{

_lpszCView , sizeof(CWnd) , FFFF,NULL , &Wnd::classCWnd , NULL);

};

static AFX_CLASSINIT _init_CWnd(&CWnd::classCWnd);

{

   Return &CWnd::classCWnd;

}


 

定义宏的过程很复杂,但是一旦定义好之后,在使用时仅仅两句话就可以完成定义CRuntimeClass对象并且连接类型型录链表的工作。

CObject是所有类的基类,也是链表的头,此类应特别定义,不能在CObject内使用定义好的宏。

class CObject

{

  public:

     virtual CRuntimeClass*GetRuntimeClass()const;

     static CRuntimeClass classCObject;

};

static char szCobject[]="CObject";

struct CRuntimeClass CObject::classCObject=

{

  szCObject ,sizeof(CObject),0xFFFF,NULL,NULL,NULL

};

static AFX_CLASSINIT _init_CObject(&Cobject::classObject);

CRuntimeClass *CObject::GetRuntimeClass()const

{

  return &CObject::classCObject;

}


 

由于CRuntimeClass对象是static成员变量,因此需要在类外初始化。如果忘记初始化将会报链接错误。

CRuntimeClass*CRuntimeClass::pFirstClass=NULL;

建好了类类型路表,要实现IsKindOf功能很容易。首先在CObject加上一个IsKindOf函数,于是所有继承自此类的类都具有类型识别的功能。能够将某个CRuntimeClass对象与类类型型录中的元素进行比较。如:

 

   class CObject

{

   public:

bool IsKindOf(const CRuntimeClass*pClass)const

{

  CRuntimeClass *pClassThis=GetRuntimeClass();

   while(pClassThis)

   {

     if(pClassThis==pClass)

       return true;

     pClassThis=pClassThis->m_pBaseClass;//沿着基类寻找。

   }

   return false;

}

};


 


如果我们调用CWnd *cw=new CWnd;

    cw->IsKindOf(RUNTIME_CLASS(CFrameWnd));

    RUNTIME_CLASS实际就是&CFrameWnd::classCFrameWnd,它就是CFrameWndstaticCRuntimeClass类型成员。函数内利用GetRuntimeClass取得本类的CRuntimeClass对象的地址,即&CWnd::classCWnd,然后进行比较。因为每一类型共用一个staticCRuntimeClass对象,因此属于同于类的CRuntimeClass对象的地址相同。

动态创建

    每一类的构建函数可以记录在类型别录中,当获得一个类名称,通过查找类别型录表找出对应的元素,然后调用其构建函数产生新对象。

    在CRuntimeClassm_pfnCreateObject即为构建函数首地址。

为了实现动态创建,需要添加两个宏:

DECLARE_DYNCREATEIMPLEMENT_DYNCREATE

如:

#define DECLARE_DYNCREATE(class_name)\

    DECLARE_DYNCREATE(class_name)\

static CObject *PASCAL CreateObject();

#define IMPLEMENT_DYNCREATE (class_name,base_class_name)\

   CObject*PASCAL class_name::CreateObject()\

   {return new classname;};\

    _IMPLEMENT_RUNTIMECLASS(class_name,base_class_name,

    0xFFFF,class_name::CreateObject)


 

CFrameWnd为例,下列程序代码:

class CFrameWnd:public CWnd

{

   public:

    DECLEARE_DYNCREATE(CFrameWnd);

};


 

IMPLEMENT_DYNCREATE(CFrameWnd,CWnd);

展开如下:

 

class CFrame:public CWnd

{

  public:

   static CRuntimeClass classCFrameWnd;

   virtual CRuntimeClass *GetRuntimeClass()const;

   static CObject *PASCAL CreateObject();

};

CObject _PASCAL CFrameWnd::CreateObject()

{

return new CFrameWnd;
}

static char _lpszCFrameWnd[]="CFrameWnd";

CRuntimeClass CFrameClass::classCFrameWnd={

 _lpszCFrameWnd,sizeof(CFrameWnd),0xFFFF,CFrameWnd::CreateObject,RUNTIME_CALSS(CWnd),NULL};

static AFX_CLASSINIT _init_CFrameWnd

                      (&CFrameWnd::classCFrameWnd);

CRuntimeClass*CFrameWnd::GetRunimeClass()const

{return &CFrameWnd::classCFrameWnd;}


 

注意对象构建函数为static函数。

为了支持动态创建需要在CRuntimeClass内添加两个函数:CreateObjectCRuntimeClass::Load成员函数。

CObject *CRuntimeClass::CreateObject()

{

   If(m_pfnCreateObject==NULL)//不支持动态创建。

    {

        throw runtime_error("此类不支持动态创建");

        Return NULL;

    }

    CObject*pObject=(*m_pfnCreateObject)();

    Return pObject;

}

CRuntimeClass*PASCL CRuntimeClass::Load()

{

   Char szClassName[64];

   CRuntimeClass*pClass

  cout<<"输入一个类名:";

  cin>>szClassName;

   for(pClass=pFirstClass;pClass;pClass=pClass->m_pNextClass)

    {

       if(strcmp(szClassName,pClass->m_lpszClassName)==0)

               return pClass;

        return NULL;

    }

}


 

以下为类型识别及动态创建的完整代码:

#include<iostream>
#include<windows.h>
#include<string>
using namespace std;

class CObject;
class CRuntimeClass
{
public:
	char* m_lpszClassName;//对象所属类名
	int m_nObjectSize;//对象大小
	int m_wSchema;//模式号
	CObject*(PASCAL*m_pfnCreateObject)();//构建函数,抽象类为NULL
	CRuntimeClass *m_pBaseClasss;//基类CRuntimeClass对象指针。
	static CRuntimeClass *pFirstClass;//链表头指针。static
	CRuntimeClass  *m_pNextClass;//下一指针。
public:
	CObject*CreateObject()
	{
		if(m_pfnCreateObject==NULL)
		{
			cout<<"该类型不支持动态创建!!"<<endl;
			return NULL;
		}
		CObject*pClass=(*m_pfnCreateObject)();
		return pClass;
	}
	static CRuntimeClass*Load()
	{
		cout<<"请输入要动态创建的类名:";
		string s;
		cin>>s;
		for(CRuntimeClass*pClass=pFirstClass;pClass;pClass=pClass->m_pBaseClasss)
		{
			if(pClass->m_lpszClassName==s)
			{
				return pClass;
			}
		}
		return NULL;
	}
};

class AFX_CLASSINIT
{
public:
    AFX_CLASSINIT(CRuntimeClass*pNewClass)//构造函数
	  { 
         pNewClass->m_pNextClass=CRuntimeClass::pFirstClass;
        CRuntimeClass::pFirstClass =pNewClass;
      }
 };

/************************************************************************/
/* 动态类型识别宏定义                
//与CRuntimeClass类中的构建函数相区别。此处的CreateObject函数在每个类中都以static成员函数存在,用以
//初始化类型型录表,而CRuntimeClass中的CreateObject用于调用每个类的构建函数。仅仅是函数名相同罢了。*/
/************************************************************************/

#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 RUNTIME_CLASS(class_name)\
	(&class_name::Class##class_name)\

#define _IMPLEMENT_RUNTIMECLASS(class_name,base_class_name,wSchema,pfnNew)\
    class CRuntimeClass class_name::Class##class_name ={\
    #class_name,\
    sizeof(class_name),wSchema,pfnNew,RUNTIME_CLASS(base_class_name),NULL};\
    static AFX_CLASSINIT _init##class_name( RUNTIME_CLASS(class_name));\
	CRuntimeClass *class_name::GetRuntimeClass()const\
    {return &class_name::Class##class_name;}//此处将class_name写成了classname花了一两天才查出来。啊啊啊啊啊。20120605


#define IMPLEMENT_DYNAMIC(class_name,base_class_name)\
	_IMPLEMENT_RUNTIMECLASS(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_RUNTIMECLASS(class_name,base_class_name,0xFFFF,class_name::CreateObject)\


/************************************************************************/
/*  对CObject特殊处理。                                                   */
/************************************************************************/
class CObject
{
public:
	CObject()
	{
		//cout<<"CObject constructor!"<<endl;
	}
	~CObject()
	{
		//cout<<"CObject destructor!"<<endl;
	}
public:
    virtual CRuntimeClass*GetRuntimeClass();
    static CRuntimeClass  ClassCObject;
public:
	bool IsKindOf(CRuntimeClass*pClass)
	{
		CRuntimeClass *pThis=GetRuntimeClass();
		for(;pThis;pThis=pThis->m_pBaseClasss)
		{
			if(pThis==pClass)
			{
				return true;
			}
		}
		return false;
	}
};
class CRuntimeClass CObject:: ClassCObject=
{
   "CObject",sizeof(CObject),0xFFFF,NULL,NULL,NULL
};
static AFX_CLASSINIT _init_CObject(&CObject:: ClassCObject);
CRuntimeClass *CObject::GetRuntimeClass()
{
	return &CObject::ClassCObject;
}
CRuntimeClass*CRuntimeClass::pFirstClass=NULL;

/************************************************************************/
/*                                                                      */
/************************************************************************/
class CCmdTarget:public CObject
{
	DECLARE_DYNCREATE(CCmdTarget)
public:
	CCmdTarget()
	{
		//cout<<"CCmdTarget constructor!"<<endl;
		//CreateObject();
	}
	~CCmdTarget()
	{
		//cout<<"CCmdTarget destructor!"<<endl;
	}	

};
IMPLEMENT_DYNCREATE(CCmdTarget,CObject)


		;
class CWnd:public CCmdTarget
{
	DECLARE_DYNCREATE(CWnd)
public:
	CWnd()
	{
		//cout<<"CWnd constructor"<<endl;
	}
	~CWnd()
	{
		//cout<<"CWnd destructor"<<endl;
	}
public:
	virtual bool Create()
	{
		cout<<"CWnd::Create"<<endl;
		CreateEx();
		return true;
	}
	bool CreateEx()
	{
		cout<<"CWnd::CreateEx"<<endl;
		PreCreateWindow();
		return true;
	}
	virtual bool PreCreateWindow()
	{
		cout<<"CWnd::PreCreateWindow"<<endl;
		return true;
	}
};
IMPLEMENT_DYNCREATE(CWnd,CCmdTarget)

class CView :public CWnd
{
	DECLARE_DYNCREATE(CView)
public:
	CView()
	{
		//cout<<"CView constructor"<<endl;

	}
	~CView()
	{
		//cout<<"CView destructor"<<endl;
	}

};
IMPLEMENT_DYNCREATE(CView,CWnd)

class CFrameWnd:public CWnd
{
	DECLARE_DYNCREATE(CFrameWnd)
public:
	CFrameWnd()
	{
		//cout<<"CFrameWnd constructor"<<endl;

	}
	~CFrameWnd()
	{
		//cout<<"CFrameWnd destructor"<<endl;
	}
public:
	virtual bool Create()
	{
		cout<<"CFrameWnd::Create"<<endl;
		CreateEx();
		return true;
	}
	virtual bool PreCreateWindow()
	{
		cout<<"CFrameWnd::PreCreateWindow"<<endl;
		return true;
	}
};
IMPLEMENT_DYNCREATE(CFrameWnd,CWnd)

class CWinThread:public CCmdTarget
{
public:
	CWinThread()
	{
		//cout<<"CWinThread constructor"<<endl;
	}
	~CWinThread()
	{
		//cout<<"CWinThread destructor"<<endl;
	}
public:
	virtual bool InitInstance()
	{
		cout<<"CWinThread::InitInstance"<<endl;
		return true;
	}
	virtual bool Run()
	{
		cout<<"CWinThread::Run"<<endl;
		return true;
	}
};
class CWinApp:public CWinThread
{
public:
	CWinApp()
	{
		//cout<<"CWinApp Constructor "<<endl;
		m_currentApp=this;
	}
	~CWinApp()
	{
		//cout<<"CWinApp destructor "<<endl;
	}
	virtual bool InitApplication()
	{
		cout<<"CWinApp::InitApplication"<<endl;
		return true;
	
	}
	virtual bool InitInstance()
	{
		cout<<"CWinApp:InitInstance"<<endl;
		return true;
	}
	virtual bool Run()
	{
		cout<<"CWinApp::Run"<<endl;
		return CWinThread::Run();
	}
public:
	CWinApp*m_currentApp;
	CFrameWnd*m_currentFrameWnd;
};
class CDocument:public CCmdTarget
{
public:
	CDocument()
	{
		//cout<<"CDocument constructor "<<endl;
	}
	~CDocument()
	{
		//cout<<"CDocunment destructor "<<endl;
	}
};
class CMyFrameWnd:public CFrameWnd
{
	DECLARE_DYNCREATE(CMyFrameWnd)
public:
	CMyFrameWnd()
	{
		//cout<<"CMyFrameWnd constructor "<<endl;
		Create();
	}
	~CMyFrameWnd()
	{
		//cout<<"CMyFrameWnd destructor "<<endl;
	}
};
IMPLEMENT_DYNCREATE(CMyFrameWnd,CFrameWnd)

class CMyWinApp:public CWinApp
{
public:
	CMyWinApp()
	{
		//cout<<"CMyWinApp constructor "<<endl;
		
	}
	~CMyWinApp()
	{
		//cout<<"CMyWinApp destructor "<<endl;
	}
public:
	bool InitInstance()
	{
		cout<<"CMyWinApp::InitInstance"<<endl;
		m_currentFrameWnd=new CMyFrameWnd;
		return true;
	}
};

CMyWinApp myApp;
CWinApp*AfxGetApp()
{
	return myApp.m_currentApp;
}
int main(int argc,char**argv)
{
	CWinApp *pApp=AfxGetApp();
	pApp->InitApplication();
	pApp->InitInstance();
	pApp->Run();

	CRuntimeClass *pClass;
	CObject *pOb;
	cout<<"以下为类型型录链表中的所有类的名称:"<<endl;
	for(pClass=CRuntimeClass::pFirstClass;pClass;pClass=pClass->m_pBaseClasss)
	{
		cout<<pClass->m_lpszClassName<<endl;
	}
	while(1)
	{
		pClass=CRuntimeClass::Load();
		if(!pClass)
		{
			cout<<"找不到此类!!!"<<endl;
		}
		else
		{
			pOb=pClass->CreateObject();
			if(pOb)
			{
				cout<<"创建成功!"<<endl;
			}

		}		
	}
	return 0;
}




 

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值