ObjectARX运行时类信息实现原理 desc() isKindOf() cast() isA() 区别和用法

作者: admin 分类: C++,CAD,ObjectARX 发布时间: 2020-09-28 20:47
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 

基础知识:

a 正常情况下,基类指针调用基类成员(成员变量和成员函数);派生类指针调用派生类成员
b 公有派生时基类指针允许指向派生类对象,但只能调用派生类继承自基类的成员而不能访问扩展部分成员
c 以私有派生时,基类指针不允许指向派生类对象
d 派生类指针不允许指向基类对象

另:基类的指针可以强制转换为派生类指针,反之不可。

静态成员函数只能对类内静态数据成员访问,也允许调用另一个静态成员函数,但不能访问其它成员。
公有的和保护的静态成员可以被继承,此时基类对象和派生对象共享静态成员。

AcRxClass是ARX所有类的基类

//desc()  isKindOf()  cast() isA()定义
static AcRxClass *   desc();
inline bool  isKindOf( const AcRxClass * aClass ) const;
virtual AcRxClass *  isA() const;
static AcRxObject *  cast( const AcRxObject * inPtr);
//下面看如下代码
AcDbEntity *pEnt = NULL;
AcDbObjectId ObjId = ObjId::kNull;
acdbOpenObject(pEnt,ObjId,AcDb::kForRead,Adesk::kFalse);
//判断是否为单行文本类型
if(pEnt->isKindOf(AcDbText::desc()))
{
    AcDbText *pText=AcDbText::cast(pEnt);//pEnt这时指的已经是AcDbText类
}

上面代友中用到了 desc() isKindOf() cast() 三个函数:
pEnt 是AcDbEntity类型的指针,AcDbEntity是AcDbText的父类,在acdbOpenObject函数中,它指向了它的某一个子类,按基础知识判断,是允许的。

isA()函数无传入参数,返回不是bool型,^_^,虽然它的名字看起来有点象。其实它的功能和 desc()很像,只是它返回的值是 this所特指的类

//isA()的示例
AcDbEntity *pEnt = NULL;
AcDbObjectId ObjId = ObjId::kNull;
acdbOpenObject(pEnt,ObjId,AcDb::kForRead,Adesk::kFalse);
//判断实体,如果不是SPLine类型则返回
if(pEnt->isA() != AcDbSpline::desc())
{
    pEnt->close();
    return;
}

https://blog.csdn.net/iMatt/article/details/85001405

https://blog.csdn.net/MM252685905/article/details/52650749

如果觉得我的文章对您有用,请随意赞赏。您的支持将鼓励我继续创作!

发表评论

标签云