文章目录
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_MEMBERS和ODRX_DXF_DEFINE_MEMBERS宏在必须为派生类指定所有RTTI信息时使用。通常使用ODRX_NO_CONS_DEFINE_MEMBERS、ODRX_CONS_DEFINE_MEMBERS和ODRX_DXF_CONS_DEFINE_MEMBERS宏。
对于需要伪构造函数的宏,使用EMPTY_CONSTR、NEWOBJ_CONSTR和RXIMPL_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和应用程序名称,第三个宏传递所有指定的参数。
暂无评论内容