主要检查一下对象否从某一类类派生,但此类必须从CObject派生(或间接),并且使用DECLARE_DYNAMIC/DECLARE_SEARIAL等宏
比如我们函数的参数是个基类的指针类型。那么当我外部传过来一个子类的指针时,在函数内部就可以用这种语句来确认传进来的是这个子类的对象,而不是其它子类的对象
ASSERT(xxx->IsKinfOf(RUNTIME_CLASS(yyy)))
判断xxx所指的类是否为yyy的子类!
指针的类型和指针指向的对象的类型可以是不一样的,这就是指针的灵活性;但是这种灵活性是不安全的,因为可以随意转换,所以前面用一个ASSERT判断一下。
其实现在在C++中也可以使用安全的类型转换:static_cast、dynamic_cast等。
======================================================================
[cpp] view plaincopy
IMPLEMENT_DYNAMIC(CDlgTest, CDialog)
CDlgTest::CDlgTest(CWnd* pParent )
: CDialog(CDlgTest::IDD, pParent)
{
...
}
3、使用时,CDlgTest dlg;
if(dlg.IsKinfOf(CDialog))...
随后又研究了一下这几个宏,也算明白了IsKindOf的实现原理,做下简单记录:
1、DECLARE_DYNAMIC宏
[cpp] view plaincopy
#define DECLARE_DYNAMIC(class_name)/
public:/
static CRuntimeClass class##class_name;/
virtual CRuntimeClass* GetRuntimeClass() const;
2、IMPLEMENT_DYNAMIC宏
[cpp] view plaincopy
#define IMPLEMENT_DYNAMIC(class_name,bass_class_name)/
_IMPLEMENT_RUNTIMECLASS(class_name,base_class_name,0xFFFF,NULL)
#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;}
3、IsKindOf函数的实现
// example for CObject::GetRuntimeClass
CAge a(21);
CRuntimeClass* prt = a.GetRuntimeClass();
ASSERT( strcmp( prt->m_lpszClassName, "CAge" ) == 0 );
Return Value:
A pointer to the CRuntimeClass structure corresponding to this object‘s class; never NULL.
[cpp] view plaincopy
BOOL CRuntimeClass::IsDerivedFrom(const CRuntimeClass *pClass) const
{
CRuntimeClass* pClassThis=this;
while(pClassThis != NULL)
{
if(pClassThis==pClass)
return TRUE;
pClassThis=pClassThis->m_pBaseClass;
}
return FALSE;
}
BOOL CObject::IsKindOf(const CRuntimeClass* pClass) const
{
ASSERT(this != NULL);
// it better be in valid memory, at least for CObject size
ASSERT(AfxIsValidAddress(this, sizeof(CObject)));
// simple SI case
CRuntimeClass* pClassThis = GetRuntimeClass();
return pClassThis->IsDerivedFrom(pClass);
}
4、单行宏的定义
定义单行宏:主要有以下三种用法.
1) 前加##或后加##,将标记作为一个合法的标识符的一部分.注意,不是字符串.多用于多行的宏定义中.例如:
#define A(x) T_##x
则 int A(1) = 10; //等效于int T_1 = 10;
#define A(x) Tx##__
则 int A(1) = 10; //等效于int T1__ = 10;
2) 前加#@,将标记转换为相应的字符,注意:仅对单一标记转换有效
#define B(x) #@x
则B(a)即 ‘a‘,B(1)即 ‘1‘.但B(abc)却不甚有效.
3) 前加#,将标记转换为字符串.
#define C(x) #x
则C(1+1) 即 "1+1".