ObjectARX运行时类信息实现原理

新公司维护基于CAD的二次开发旧代码。学习ObjectARX相关的内容。

先看原始代码

class MyClass: public AcRxObject
{
public:
	virtual AcRxClass* isA() const
	{
		if (MyClass::gpDesc != NULL)
			return MyClass::gpDesc; 
		return MyClass::gpDesc
        = (AcRxClass*)((AcRxDictionary*)acrxSysRegistry()
			->at(ACRX_CLASS_DICTIONARY))->at(ACRX_T(#MyClass));
	}
    static AcRxClass* gpDesc;
    static AcRxClass* desc()
	{
		if (MyClass::gpDesc != NULL)
			return MyClass::gpDesc;
		return MyClass::gpDesc = (AcRxClass*)((AcRxDictionary*)acrxSysRegistry()
        ->at(ACRX_CLASS_DICTIONARY))->at( ACRX_T(#MyClass) );
	}
    static MyClass* cast(const AcRxObject* inPtr)
    { 
		return ((inPtr == NULL) || !inPtr->isKindOf(MyClass::desc()))
          ? NULL : (MyClass*)inPtr; 
	}
#if 0 	//第一套方案
    static void rxInit()
	{    
		if (MyClass::gpDesc) 
		{
			AcRxClass *pClass =
			(AcRxClass*)((AcRxDictionary*)acrxSysRegistry()
				->at(ACRX_CLASS_DICTIONARY))->at(ACRX_T(#MyClass));
			if (pClass) 
			{
				if (MyClass::gpDesc == pClass)
					return;
				else
					acrx_abort(ACRX_T(/*MSGO*/"Class mismatch"));
			}
		}
		MyClass::gpDesc = 
			newAcRxClass(ACRX_T(#MyClass), ACRX_T(#MyClass));
	}
    static void rxInit(AppNameChangeFuncPtr);
	
#else
	
	static AcRxObject * make##MyClass() { return new MyClass(); } \
	void rxInit() 
	{
		
		if (MyClass::gpDesc) 
		{
			AcRxClass *pClass =
			(AcRxClass*)((AcRxDictionary*)acrxSysRegistry()
				->at(ACRX_CLASS_DICTIONARY))->at(ACRX_T(#MyClass));
			if (pClass) 
			{
				if (MyClass::gpDesc == pClass)
					return;
				else
					acrx_abort(ACRX_T(/*MSGO*/"Class mismatch"));
			}
		}
		MyClass::gpDesc = newAcRxClass(ACRX_T(#MyClass), ACRX_T(#PARENT_CLASS),
        VERNO, &make##MyClass);
	}

#endif

static AcRxObject * make##MyClass() { return new MyClass(); }
void MyClass::rxInit() 
{
	ACRX_STATIC_CHECK(MyClass);
	MyClass::gpDesc = newAcRxClass(ACRX_T(#MyClass), ACRX_T(#PARENT_CLASS),
		DWG_VERSION,MAINTENANCE_VERSION,PROXY_FLAGS, 
		&make##MyClass, ACRX_T(#DXF_NAME), ACRX_T(#APP));
}
void MyClass::rxInit(AppNameChangeFuncPtr ptr) {
	ACRX_STATIC_CHECK(MyClass);
	MyClass::gpDesc = newAcRxClass(ACRX_T(#MyClass), ACRX_T(#PARENT_CLASS),
	DWG_VERSION,MAINTENANCE_VERSION,PROXY_FLAGS, 
	&make##MyClass, ACRX_T(#DXF_NAME), ACRX_T(#APP), ptr);
}

	
};	
AcRxClass* MyClass::gpDesc = NULL;

inline bool AcRxObject::isKindOf(const AcRxClass* pOtherClass) const
{
    const AcRxClass * pMyClass = this->isA();
    return pMyClass == NULL ? false : pMyClass->isDerivedFrom(pOtherClass);

}
void test( )
{
  AcDbEntity *pEnt...;
  if(pEnt->isA()==AcDbLine::desc())
  {
	  //实体正好是一条线段
  }



 if(pEnt->isKindOf(AcDbLine::desc()) 
 {
	 AcDbLine* pLine = AcDbLine::cast(pEnt); 
	 //要判断实体是线段或者线段的派生对象
 }

}

实现原理:

AcRxObject类及其派生类的静态成员gpDesc(AcRxClass类型)存储了运行时信息,在加载过程中完成初始化,同时会将此类注册到ObjectARX也会加入到系统的acrxClassDictionary中。

AcRxObject中相关的成员函数:

desc(),static,返回AcRxObject类(及其派生类)的运行时类信息描述符(对象);

cast(),static,返回指定对象的运行时类信息对象,如果不是这个类(或其子类),返回NULL;

isKindOf (),判断指定对象是否属于这个类(或其派生类);

isA(),返回对象自己的运行时类信息描述符。

 

=============================================
AcRxClass是 AcRxObject类(及其派生类)的运行时类信息类。
AcRxClass保存了当前类及其父类的关系等相关数据
AcRxObject::isA 和AcRxObject::desc功能类似。
前者是多态性体现着,后者是类的静态数据(绝对).
前者用于动态创建的对象,后者用于得到具体类类型信息.
cast用于进行具体转换。
kindof调用isA,再从类型信息树中递归查询信息。
注意:cast中调用了isKindOf 

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 技术黑板 设计师:CSDN官方博客 返回首页