Teigha SDK Developer 运行时类型识别 #1

文章目录

Kernel SDK Developer’s Guide

Run-Time Type Identification

Concept of RTTI Technology

运行时类型标识(RTTI)技术提供了动态标识类并在运行时获取有关类的各种信息的能力。RTTI允许开发者:

  • 检查实例是否属于指定的类;
  • 在处理数据之前,检查指针到指定类型的转换是否正确;
  • 检查指定实例的函数或方法应用程序是否正确;
  • 根据指定实例的类类型选择数据处理方式;
  • 获取指定类的描述信息;
  • 开发更灵活的程序代码,以适应不同的数据类型。

如果实例属于或派生自指定的类,则可以将指向实例的指针转换为特定的类类型,对实例应用方法是正确的。实例识别后,开发人员可以对其数据进行特定的处理,可以调用特定的函数或方法,可以应用所允许的操作。
运行时类型标识的思想是使用存储类信息的数据的特殊结构,并从类的实例引用这个结构。
派生自OdRxObject类的类的每个实例都存储指向描述其类的结构的原始指针。关于类的信息存储在特殊结构中。使用指向描述结构的指针,实例可以在任何时候获得关于它自己的类的信息。此外,每个派生类必须定义方法,这些方法允许它自己的对象获得指向描述结构的指针,检查它是属于类还是属于子类,验证父类,并获取标识信息。所有的描述结构通常统一在一个类字典中;重复单个类的描述是没有必要的。
运行时类型识别技术的实现包括声明和实现特殊存储类的描述,声明和实现获取和检查来自OdRxObject类的类信息的方法,声明和实现注册和取消注册类类型的特殊函数,实现操作描述结构的函数。描述结构的一个实例存储关于一个类类型的信息。一个类类型的多个实例可以引用一个描述结构。每个描述结构都存储对结构的引用,该结构在类的层次结构中描述自己的父类。该实现还包括一个特殊的字典,它将类名与其描述结构联系起来。
在这里插入图片描述
运行时类型识别技术的实现提供了以下功能:

  • 在运行时获取类名。
  • 获取有关父类的信息。
  • 获取dxf类名并将其与类关联。
  • 获取应用程序类名并将其与类关联。
  • 获取有关类所在的模块的信息。
  • 检查类是否派生自指定的类。
  • 获取或设置类的伪构造函数。
  • 获取或设置将绘图保存到文件时调用的回调函数。
  • 获取类版本。
  • 获取代理和自定义标志。
  • 使用类的字典。
  • 提供“协议扩展”技术。

Overview of Classes that Implement RTTI

c++平台支持RTTI(运行时类型标识)技术,该技术提供了一种方法来验证和获取有关类的各种信息,并在运行时创建类实例。要使用RTTI,请使用以下方法:

OdRxObject abstract class
OdRxClass abstract class
OdRxClassProtocolExtImpl, OdRxBaseClassImpl, OdRxClassConsImpl, OdRxNamedClassImpl, OdDxfClassImpl classes
newOdRxClass and deleteOdRxClass global functions
Class dictionary
RTTI Macros

OdRxObject class

OdRxObject抽象类为所有使用RTTI的类提供了基本接口,仅用于派生类。您不能创建此类的实例。它的纯虚方法没有实现,是派生类的RTTI接口的声明。它声明了以下RTTI方法:

desc() static method — Returns the class describing instance statically associated with the class.
isA() virtual method — Returns the class describing instance dynamically associated with the class.
isKindOf() method, queryX() virtual method, x() virtual method — Checks whether the instance belongs to the specified class or its subclass.
pseudoConstructor() static method — Creates an instance of the class using the default static pseudo-constructor and returns the typified smart pointer to the created instance.
createObject() static method — Creates an instance of the class using the pseudo-constructor defined by the class describing instance and returns the non-typified smart pointer to the created instance.
rxInit() static method — Registers the class.
rxUninit() static method — Unregisters the class.

OdRxClassProtocolExtImpl, OdRxBaseClassImpl, OdRxClassConsImpl, OdRxNamedClassImpl, OdDxfClassImpl classes
OdRxClassProtocolExtImpl、OdRxBaseClassImpl、OdRxClassConsImpl、OdRxNamedClassImpl和OdDxfClassImpl类实现了描述实例的类。它们添加新成员,并为派生自OdRxClass类的类创建纯虚拟方法的标准实现。

newOdRxClass and deleteOdRxClass global functions

newOdRxClass全局函数在程序中注册该类。它使用上面列出的实现类创建和初始化描述实例的类。其实例用作描述实例的类的主类是OdDxfClassImpl类。OdRxClass类是OdRxObject类的继承者,继承了numRefs()、addRef()和release()虚拟方法;newOdRxClass()函数还使用OdRxObjectImpl类在引用计数的标准实现中包装OdDxfClassImpl类。然后newOdRxClass()函数调用OdDxfClassImpl类的init()方法来初始化关于该类的信息,并在类字典中添加关于该类的新记录。
deleteOdRxClass全局函数在程序中注销该类。它从类字典中删除类信息,并使用release()方法销毁类描述实例。
rxInit()静态方法使用newOdRxClass()全局函数在程序中注册该类。rxUninit()静态方法使用deleteOdRxClass()全局函数从程序中注销该类。

Class dictionary

类字典是现有的dictionary对象,它存储关于程序中注册的所有类的信息。odInitialize()全局函数创建类字典并使用预定义的类名初始化它。全局函数的作用是:返回类dictionary对象的智能指针。类字典允许开发人员在运行时操作所描述的类。odrxCreateObject()全局函数允许使用类名和类字典对象创建类实例。

RTTI macros

The ODRX_DECLARE_MEMBERS, ODRX_DEFINE_RTTI_MEMBERS, ODRX_DEFINE_INIT_MEMBERS, ODRX_DEFINE_PSEUDOCONSTRUCTOR, ODRX_DEFINE_MEMBERS2, ODRX_DEFINE_MEMBERS, ODRX_DXF_DEFINE_MEMBERS, ODRX_NO_CONS_DEFINE_MEMBERS, ODRX_CONS_DEFINE_MEMBERS, ODRX_NO_CONS_DEFINE_MEMBERS_ALTNAME, ODRX_CONS_DEFINE_MEMBERS_ALTNAME, ODRX_DXF_CONS_DEFINE_MEMBERS macros generate the implementation for the RTTI methods

Implementing the Class Describing Structure

OdRxClass抽象类是存储类信息的描述结构。在应用程序中注册的每个类都必须具有描述结构的类的实例。所有的类描述实例构成类的字典(命名类字典)。
OdRxClass抽象类提供了获取和存储类信息的基本接口,仅用于派生新类。您不能创建OdRxClass类的实例。OdRxClass抽象类继承了OdRxObject类的功能。它声明了以下方法:

name() pure virtual method — Returns the class name.
dxfName() pure virtual method — Returns the dxf class name.
appName() pure virtual method — Returns the application class name.
getClassVersion() pure virtual method — Returns the maintenance version.
proxyFlags() pure virtual method — Returns the proxy flags.
customFlags() pure virtual method — Returns the custom flags.
constructor() virtual method — Returns the pseudo-constructor of the class.
setConstructor() pure virtual method — Sets the pseudo-constructor of the class.
appNameCallbackPtr() pure virtual method — Returns a pointer to the function called when a drawing is being saved to a file.
create() pure virtual method — Creates an instance of the class using its pseudo-constructor.
module() pure virtual method — Returns the raw pointer to the OdRxModule object associated with this class.
myParent() pure virtual method — Returns the raw pointer to the OdRxClass object that is the parent for this class.
addX(), delX() and getX() — Adds, deletes, and gets the protocol extension record.

这些方法没有实现,它们是运行时类型标识接口的声明。派生自OdRxClass类的类必须重新定义这些方法。
c++平台有以下类来实现由OdRxClass类声明的纯方法:

OdRxClassProtocolExtImpl类——派生自OdRxClass类,实现基本的运行时成员和协议扩展功能,并添加addX()delX()getX()方法的实现。
OdRxBaseClassImpl类——派生自OdRxClassProtocolExtImpl类,声明存储关于模块和父类的信息的成员,将描述的类与其模块关联起来,并添加了module()myParent()方法的实现。
OdRxClassConsImpl类——派生自OdRxBaseClassImpl类,声明将类的伪构造函数存储为OdPseudoConstructorType类型的成员,并添加create()constructor()setConstructor()方法的实现。
OdRxNamedClassImpl类——派生自OdRxClassConsImpl类,声明将类名存储为OdString值的成员,并添加name()方法的实现。
OdDxfClassImpl来源于OdRxNamedClassImpl类,声明的成员存储dxf类名作为OdString值,应用程序类名作为OdString价值,维护版本作为OdUInt16值,.dwg文件版本作为OdUInt16值,代理旗帜作为OdUInt32值,并添加的实现dxfName(),浏览器名称(),proxyFlags(),getClassVersion()方法。

OdRxClassProtocolExtImpl类还创建的默认实现create()方法返回空指针,不创建一个实例,该setConstructor()方法生成eNotApplicable例外,这个dxfName()方法,它返回一个空字符串,该浏览器名称()方法,它返回一个空字符串,和getClassVersion()方法,它返回kMRelease0(= 0)版本号。
OdRxClassConsImpl类通过空的伪构造函数初始化描述实例的类。如果setConstructor()方法获得NULL而不是伪构造函数,则默认设置空的伪构造函数。如果描述实例的类有一个空的伪构造函数,那么create()方法将生成enotapplied异常,而不是创建一个实例。
OdPseudoConstructorType类型是指向函数的原始指针,该函数不接受参数,并返回非类型化的智能指针,以指向该函数创建的类的实例。这种类型的定义如下:
typedef OdRxObjectPtr (*OdPseudoConstructorType)()
列出的每个类都声明并实现自己的init()方法,该方法根据指定的值初始化类的成员。通常使用OdDxfClassImpl类。
列出的类构成如下层次结构:
在这里插入图片描述
通常,您不需要创建这些类的实例。RTTI替换宏自动生成rxInit()方法的实现,该方法调用newOdRxClass()全局函数来在应用程序中注册类。这个函数自动创建并初始化OdDxfClassImpl类的实例,并使用OdRxObjectImpl类包装它,以实现引用计数方法。函数的作用是:返回一个原始指针,指向创建的描述OdRxClass类型实例的类。rxInit()方法将这个指针存储在创建描述实例的类的实例的g_pDesc成员中。

Implementing RTTI Methods for the Derived Class

从OdRxObject抽象类派生类时,您可以使用OdRxObjectImpl模板类或OdStaticRxObject模板类来实现引用计数并将抽象类转换为实际类。例如:

class xSomeObj : public OdRxObjectImpl<OdRxObject>
{
 public:
   xSomeObj();
   ~xSomeObj();
};

但是这些模板类并不创建RTTI方法的实现。基本的RTTI功能只在OdRxObject类中声明。每个派生自OdRxObject类的类必须自己重新定义RTTI方法。要重新定义RTTI方法,请使用ODRX_DECLARE_MEMBERS宏来重新定义派生类的下列标准RTTI成员

g_pDesc static member — The raw pointer to the class describing structure.
cast() static method — Casts the specified raw pointer to the smart pointer of the derived class.
desc() static method — Returns the raw pointer to the class describing instance.
isA() virtual method — Returns the raw pointer to the class describing instance.
queryX() virtual method — Checks whether the instance belongs to the class being defined.
pseudoConstructor() static method — Creates a new instance of the derived class.
createObject() static method — Creates a new instance of the derived class.
rxInit() static method — Registers the derived class in the application.
rxUninit() static method — Unregisters the derived class in the application.

cast()和createObject()方法是内联方法,这个宏自动创建它们的实现。在派生自己的类时,必须在类定义语法构造的“public:”部分使用ODRX_DECLARE_MEMBERS宏。

class xSomeObj : public OdRxObjectImpl<OdRxObject>
{
 public:
   ODRX_DECLARE_MEMBERS(xSomeObj);

   xSomeObj();
   ~xSomeObj();
};

如果在项目属性中设置“生成预处理文件”(选项/P /EP)并使用这个类声明编译源文件,则在I-file中可以看到宏替换的结果。该宏将在以下行中进行转换:

class xSomeObj : public OdRxObjectImpl<OdRxObject>
{
 public:
   static OdRxClass* g_pDesc; 
   static OdRxClass* desc(); 
   virtual OdRxClass* isA() const; 
   virtual OdRxObject* queryX(const OdRxClass* protocolClass) const; 
   static OdRxObjectPtr pseudoConstructor(); 
   static OdSmartPtr<xSomeObj> createObject() 
          { 
             if (!desc()) throw OdError(eNotInitializedYet); 
             return desc()->create(); 
          } 
   static OdSmartPtr<xSomeObj> cast(const OdRxObject* pObj) 
          {   
             if (pObj) return OdSmartPtr<xSomeObj>(((xSomeObj*)pObj->queryX(xSomeObj::desc())), kOdRxObjAttach); 
             return (xSomeObj*)0; 
          } 
   static void rxInit(); 
   static void rxInit(AppNameChangeFuncPtr m_appNameChangeFunc); 
   static void rxUninit();
 
   xSomeObj();
   ~xSomeObj();
};

声明之后,使用以下宏在自己的cppi模块中创建RTTI方法的实现:

  • ODRX_DEFINE_RTTI_MEMBERS — 创建desc()、isA()和queryX()方法的默认实现,并需要类名和父类名;
  • ODRX_DEFINE_INIT_MEMBERS — 创建rxInit()和rxUninit()方法的默认实现,并需要类名、父类名、伪构造函数名、.dwg文件版本、维护版本、代理标志、dwg类名、dxf类名、应用程序类名和自定义标志;
  • ODRX_DEFINE_PSEUDOCONSTRUCTOR — 创建pseudoConstructor()方法的默认实现,并要求类名和伪构造函数替换生成实现代码的宏名;
  • ODRX_DEFINE_MEMBERS —创建所有RTTI方法的默认实现使用ODRX_DEFINE_RTTI_MEMBERS ODRX_DEFINE_INIT_MEMBERS, ODRX_DEFINE_PSEUDOCONSTRUCTOR 宏和要求类名,父类的名字,pseudo-constructor替换宏名称,.dwg文件版本号,维护版本号,代理旗帜,dwg类名,dxf类名,应用程序类名和自定义标记;
  • ODRX_DEFINE_MEMBERS2 — 类似地使用ODRX_DEFINE_MEMBERS宏创建RTTI方法的默认实现,但它不创建伪构造函数的实现(您必须实现自己的伪构造函数);
  • ODRX_NO_CONS_DEFINE_MEMBERS — 创建RTTI方法的默认实现,包括指定的类名、指定的父类名、空的伪构造函数、零版本号、零代理标志、零自定义标志、空的dxf和应用程序名、与类名一致的dwg类名,并使用ODRX_DEFINE_MEMBERS2宏。为了实现空的伪构造函数,它使用EMPTY_CONSTR替换宏。它需要类名和父类名;
  • ODRX_NO_CONS_DEFINE_MEMBERS_ALTNAME — 类似地使用ODRX_NO_CONS_DEFINE_MEMBERS宏创建RTTI方法的默认实现,但是允许指定另一个dwg类名。
  • ODRX_CONS_DEFINE_MEMBERS — 使用指定的类名、指定的父类名、零版本号、零代理标志、零自定义标志、空dxf和应用程序名、dwg类名(与类名一致)创建RTTI方法的默认实现,并使用ODRX_DEFINE_MEMBERS2宏。该宏使用ODRX_DEFINE_PSEUDOCONSTRUCTOR宏和NEWOBJ_CONSTR、RXIMPL_CONSTR或用户定义的伪构造函数替换宏来实现伪构造函数。它需要类名、父类名和替换宏名;
  • ODRX_CONS_DEFINE_MEMBERS_ALTNAME — 类似地使用ODRX_CONS_DEFINE_MEMBERS宏创建RTTI方法的默认实现,但是它允许您指定另一个dwg类名;
  • ODRX_DXF_DEFINE_MEMBERS — 使用指定的版本号、代理标志、dxf名称、应用程序名称、类名称、父类名称和用户定义的伪构造函数替换宏来创建RTTI方法的默认实现。所有信息都是必需的;
  • ODRX_DXF_CONS_DEFINE_MEMBERS — 使用指定的版本号、代理标志、dxf名称、应用程序名称、类名称、父类名称创建RTTI方法的默认实现,但是使用NEWOBJ_CONSTR替换宏实现默认的伪构造函数,并生成与类名称一致的dwg类名称。通常使用ODRX_DEFINE_RTTI_MEMBERS、ODRX_DEFINE_INIT_MEMBERS、ODRX_DEFINE_PSEUDOCONSTRUCTOR和ODRX_DEFINE_MEMBERS2宏作为辅助宏。TheODRX_DEFINE_MEMBERSODRX_DXF_DEFINE_MEMBERS宏在必须为派生类指定所有RTTI信息时使用。通常使用ODRX_NO_CONS_DEFINE_MEMBERSODRX_CONS_DEFINE_MEMBERSODRX_DXF_CONS_DEFINE_MEMBERS宏。
    对于需要伪构造函数的宏,使用EMPTY_CONSTRNEWOBJ_CONSTRRXIMPL_CONSTR替换头文件中定义的宏,生成实现伪构造函数的代码。EMPTY_CONSTR替换宏生成空的伪构造函数,该构造函数强制转换空指针。NEWOBJ_CONSTR替换宏生成伪构造函数,该构造函数创建指定类的新实例,创建指向该类的智能指针,不增加其引用计数器,并将智能指针返回给实例。RXIMPL_CONSTR替换宏生成伪构造函数,该构造函数使用该类的createObject()静态方法创建指定类的新实例,并使用OdRxObjectImpl模板包装它。这些替换宏具有以下实现
#define EMPTY_CONSTR(ClassName)   (ClassName*)0
#define NEWOBJ_CONSTR(ClassName)  OdSmartPtr<ClassName>(new ClassName, kOdRxObjAttach)
#define RXIMPL_CONSTR(ClassName)  OdRxObjectImpl<ClassName>::createObject()

当为类创建实例并不复杂时,可以定义自己的替换宏
要创建RTTI方法的标准实现,请在cpp-模块中传递ODRX_CONS_DEFINE_MEMBERS宏:
ODRX_CONS_DEFINE_MEMBERS(xSomeObj, OdRxObject, NEWOBJ_CONSTR);
要使用空的伪构造函数创建实现,请在cpp-模块中传递ODRX_NO_CONS_DEFINE_MEMBERS宏:
ODRX_NO_CONS_DEFINE_MEMBERS(xSomeObj, OdRxObject);
要创建标准实现并重新定义所有信息,请在cpp-模块中传递ODRX_DEFINE_MEMBERS宏:
ODRX_DEFINE_MEMBERS(xSomeObj, OdRxObject, RXIMPL_CONSTR, 3, 2, 36, “MyRxClass”, “acMYCLASS”, “MyApp”);
如果在项目属性中设置“生成预处理文件”(选项/P /EP)并编译cppi文件,则可以在I-file中看到替换这些宏的结果。ODRX_CONS_DEFINE_MEMBERS宏将在以下几行中进行转换:

OdRxClass* xSomeObj::g_pDesc = 0; 
OdRxClass* xSomeObj::desc() {  return g_pDesc;  } 
OdRxClass* xSomeObj::isA() const { return g_pDesc;  } 

OdRxObject* xSomeObj::queryX(const OdRxClass* pClass) const 
{ 
  return ::odQueryXImpl<xSomeObj,OdRxObject>(this, pClass); 
} 
void xSomeObj::rxUninit() 
{
  if(xSomeObj::g_pDesc) 
  { 
    ::deleteOdRxClass(xSomeObj::g_pDesc); 
    xSomeObj::g_pDesc = 0; 
  } 
  else {  throw OdError(eNotInitializedYet);  } 
} 
void xSomeObj::rxInit() 
{
  if(!xSomeObj::g_pDesc) 
  {   xSomeObj::g_pDesc = ::newOdRxClass( ((const OdChar*)L"xSomeObj"), OdRxObject::desc(), 
                                          xSomeObj::pseudoConstructor, 0, 0, 0, OdString::kEmpty, OdString::kEmpty, NULL, 0 );  } 
  else {  throw OdError(eExtendedError);  } 
}
void ClassName::rxInit(AppNameChangeFuncPtr pAppNameChangeCallback)                                  
{                                                                                                    
  if(!xSomeObj::g_pDesc) {                                                                         
    xSomeObj::g_pDesc = ::newOdRxClass( ((const OdChar*)L"xSomeObj"), OdRxObject::desc(),                          
                                          xSomeObj::pseudoConstructor, 0, 0, 0, OdString::kEmpty, OdString::kEmpty, pAppNameChangeCallback, 0); 
  } else { throw OdError(eExtendedError);  }
}
OdRxObjectPtr xSomeObj::pseudoConstructor() 
{ 
  return OdRxObjectPtr(OdSmartPtr<xSomeObj>(new xSomeObj, kOdRxObjAttach)); 
}
The result of transforming the ODRX_NO_CONS_DEFINE_MEMBERS macro will differ only by implementation of the pseudoConstrutor() and rxInit() methods and will have the following lines:

void xSomeObj::rxInit() 
{
  if(!xSomeObj::g_pDesc) 
  {   xSomeObj::g_pDesc = ::newOdRxClass( ((const OdChar*)L"xSomeObj"), OdRxObject::desc(), 
                                          0, 0, 0, 0, OdString::kEmpty, OdString::kEmpty, NULL, 0);  } 
  else {  throw OdError(eExtendedError); } 
} 
OdRxObjectPtr xSomeObj::pseudoConstructor() {  return OdRxObjectPtr((xSomeObj*)0);  }

转换ODRX_NO_CONS_DEFINE_MEMBERS宏的结果只会因实现pseudotor()和rxInit()方法而有所不同,并且会有以下几行:

void xSomeObj::rxInit() 
{
  if(!xSomeObj::g_pDesc) 
  {   xSomeObj::g_pDesc = ::newOdRxClass( ((const OdChar*)L"xSomeObj"), OdRxObject::desc(), 
                                          0, 0, 0, 0, OdString::kEmpty, OdString::kEmpty, NULL, 0);  } 
  else {  throw OdError(eExtendedError); } 
} 
OdRxObjectPtr xSomeObj::pseudoConstructor() {  return OdRxObjectPtr((xSomeObj*)0);  }

通过实现pseudotor()和rxInit()方法,转换ODRX_NO_CONS_DEFINE_ MEMBERS宏的结果会有所不同,并且会有以下代码行:

void xSomeObj::rxInit() 
{
  if(!xSomeObj::g_pDesc) 
  {   xSomeObj::g_pDesc = ::newOdRxClass( "MyRxClass", OdRxObject::desc(),xSomeObj::pseudoConstructor, 3, 2, 36, "acMYCLASS", "MyApp", NULL, 0);  } 
  else {  throw OdError(eExtendedError);  } 
} 
OdRxObjectPtr xSomeObj::pseudoConstructor() {  return OdRxObjectPtr(OdRxObjectImpl<xSomeObj>::createObject());  }

所有宏都使用newOdRxClass()全局函数来注册派生类,使用deleteOdRxClass()全局函数来注销这些实现中的派生类。第一个和第二个宏传递0个版本号、0个代理标志、空的dxf和应用程序名称,第三个宏传递所有指定的参数。

 
© 版权声明
THE END
喜欢就支持一下吧
点赞609赞赏 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容