本章主要介绍<b>Open</b> <b>CASCADE</b>的基本功能,如内存管理(<b>memory</b> <b>management</b>)、手柄编程(<b>programming</b> <b>with</b> <b>handles</b>)、基本类型(<b>primitive</b> <b>types</b>)、异常处理(<b>exception</b> <b>handling</b>)、泛型编程(<b>genericity</b> <b>by</b> <b>downcasting</b>)、<b>Plug</b>-<b>in</b>的创建等……
一、数据类型 <b>Data</b> <b>Types</b>
1.1 基本类型 <b>Primitive</b> <b>Types</b>
基本类型是由语言定义的且他们是由值控制的。有些基本类型从类<b>Storable</b>继承而来。这就意味着他们可以在持久性对象中使用,或者被包含在对象的方法中,或者作为对象内部的一部分。由类<b>Standard</b>_<b>Storable</b>派生的类有:
l <b>Boolean</b>: 用来表示逻辑数据。只有两种状态:<b>Standard</b>_<b>True</b>和<b>Standard</b>_<b>False</b>;
l <b>Character</b>: 用来表示任意<b>ASCII</b>字符;
l <b>ExtCharacter</b>: 用来表示字符的扩展;
l <b>Integer</b>: 用来表示整数;
l <b>Real</b>: 用来表示实数;
l <b>ShortReal</b>: 用来表示实数的另一种选择,精度要低;
也有非存储类型,如:
l <b>CString</b>:
l <b>ExtString</b>:
l <b>Address</b>:
下表所示为<b>Open</b> <b>CASCADE</b>中基本类型与<b>C</b>++中基本类型对应表:
<b>C</b>++ <b>Types</b>
<b>Open</b> <b>CASCADE</b> <b>Types</b>
<b>int</b>
<b>Standard</b>_<b>Integer</b>
<b>double</b>
<b>Standard</b>_<b>Real</b>
<b>float</b>
<b>Standard</b>_<b>ShortReal</b>
<b>unsigned</b> <b>int</b>
<b>Standard</b>_<b>Boolean</b>
<b>Standard</b>_<b>False</b> = 0;
<b>Standard</b>_<b>True</b> = 1;
<b>char</b>
<b>Standard</b>_<b>Character</b>
<b>short</b>
<b>Standard</b>_<b>ExtCharacter</b>
<b>char</b>*
<b>Standard</b>_<b>CString</b>
<b>void</b>*
<b>Standard</b>_<b>Address</b>
<b>short</b>*
<b>Standard</b>_<b>ExtString</b>

具体请参考《<b>Open</b> <b>CASCADE</b> <b>Foundation</b> <b>Classes</b> <b>User</b>'<b>s</b> <b>Guide</b>》;
1.2 由值控制的类型
由值控制的变量类型分为三类:
l 基本类型;
l 枚举类型;
l 不是由类<b>Standard</b>_<b>Persistent</b>直接或间接派生的类;
由值控制的变量比由手柄控制的变量更直接,更快,就是不能保存到文件。
1.3 由引用控制的类型
由手柄控制的变量分为两类:
l 由类<b>Persistent</b>派生的类,这种类可以保存到文件;
l 由类<b>Transient</b>派生的类;
1.4 属性的结论
二、手柄编程 <b>Programming</b> <b>with</b> <b>Handles</b>
2.1 手柄定义 <b>Handle</b> <b>Definition</b>
手柄与<b>C</b>++的指针(<b>pointer</b>)类似。几个手柄可以引用同一个对象,同样地,一个手柄也可以引用了几个对象,但是一次只能是一个对象。为了访问引用的对象,必须先解除引用(<b>de</b>-<b>referenced</b>),就像使用<b>C</b>++的指针一样。临时变量和持久变量既可以是由值控制的也可以是由手柄控制的。引用非持久性对象的手柄称为不可存储手柄。因此,持久性对象不能包含不可存储手柄。
类的组织:使用手柄的类的对象可以是持久的也可是临时的。从类<b>Standard</b>_<b>Transient</b>继承的类的实例是临时的,而从类<b>Standard</b>_<b>Persistent</b>继承的类的实例是持久的。本章只讨论临时类及其相关的手柄。持久类及其相关的手柄的组织与此类似。
类<b>Standard</b>_<b>Transient</b>是<b>Open</b> <b>CASCADE</b>中由手柄控制的类层次结构中的基类。它有引用计数部分,所有的子类都继承此部分。当使用<b>Handle</b>()类时,就可知引手柄引用实例的数量。
直接或间接由类<b>Transient</b>派生的类,<b>CDL</b> <b>extractor</b>将创建类的相应的手柄<b>Handle</b>(),类名是相同的,只是在类名前加上了“<b>Handle</b>_*”。<b>Open</b> <b>CASCADE</b>提供预处理器的宏定义<b>Handle</b>(),用来产生相应类的带手柄的类。
使用手柄:在对临时对象执行任何操作之前,你必须声明手柄。如:若点(<b>Point</b>)和线(<b>Line</b>)是从包<b>Geom</b>中定义的两个临时对象,代码如下:
声明手柄创建了一个未指向任何对象的空手柄。手柄可以通过其方法<b>IsNull</b>()来验证。使用手柄无效,可使用方法<b>Nullify</b>()。
只要类型兼容,既可以从创建新的对象或通过赋值来初始化手柄。手柄仅用于共享的对象。对于所有的本地操作,建议使用由值控制的类。
2.2 类型管理 <b>Type</b> <b>Management</b>
<b>Open</b> <b>CASCADE</b>提供一种描述数据类型层次的通用方式,并且可以运行时检查对象类型,与<b>C</b>++的<b>RTTI</b>类似。对于从类<b>Standard</b>_<b>Transient</b>继承的每个类,<b>CDL</b> <b>extractor</b>从类<b>Standard</b>_<b>Type</b>创建代码。由类<b>Standard</b>_<b>Transient</b>派生的类的虚函数<b>DynamicType</b>()返回一个实例。通过虚函数<b>IsKind</b>()来检查给定的对象是不是指定的类型。
2.3 使用手柄创建对象 <b>Using</b> <b>Handles</b> <b>to</b> <b>Create</b> <b>Objects</b>
创建由手柄控制的对象,声明手柄并使用标准<b>C</b>++的<b>new</b>操作符,紧随其后调用构造函数。
与指针不同的是,手柄不需要<b>delete</b>。因为当手柄引用的对象为零时,对象将会被自动释放。
2.4 方法调用 <b>Invoking</b> <b>Methods</b>
当你使用手柄的时候,就跟使用<b>C</b>++的指针一样。调用手柄引用对象的方法使用操作符->。检查或修改手柄的状态,通过操作符点.来实现。下例所示为访问一个点对象的坐标:
下例所示为如何检查笛卡尔坐标点的类型:
当调用一个空<b>Null</b>手柄时,<b>NullObject</b>异常将会产生。
调用类方法:类方法就是<b>C</b>++类中的静态函数。即用类名加上“::”和方法名来调用。
2.5 手柄释放 <b>Handle</b> <b>De</b>-<b>allocation</b>
在删除一个对象之前,必须其没有被引用。为了减少管理对象生命周期的编程工作量,<b>Open</b> <b>CASCADE</b>中对象的删除函数是由手柄控制类的引用计数(<b>reference</b> <b>counter</b>)来确保。手柄就是用来管理引用计数,当对象不再引用时将会调用<b>delete</b>将其删除。当是<b>Standard</b>_<b>Transient</b>的子类时,通常不需要直接使用<b>delete</b>操作符。当对相同的对象使用<b>new</b>时,引用计数将会增加。当手柄被销毁、置为空或重新赋值,引用计数将会减少。当引用计数为0时对象将会自动调用<b>delete</b>操作符。内存分配的原理如下所示:
<b>Cycles</b>
本段内容不清楚,具体内容请参考原文。
2.6 不使用<b>CDL</b>创建类 <b>Creating</b> <b>Transient</b> <b>Classes</b> <b>without</b> <b>CDL</b>
尽管可用<b>CDL</b> <b>extractor</b>生成手柄类及其相关<b>C</b>++代码,然而也可不用<b>CDL</b>管理手柄。为此,在文件<b>Standard</b>_<b>DefineHandle</b>.<b>hxx</b>中提供了几个宏定义:
<b>DECLARE</b>_<b>STANDARD</b>_<b>HANDLE</b>(<b>class</b>_<b>name</b>, <b>ancestor</b>_<b>name</b>) 这个宏定义了以<b>class</b>_<b>name</b>为类名并继承类<b>ancestor</b>_<b>name</b>的手柄类。这个宏必须放在头文件中,且基类必须是可用的。
<b>IMPLEMENT</b>_<b>STANDARD</b>_<b>HANDLE</b>(<b>class</b>_<b>name</b>, <b>ancestor</b>_<b>name</b>) 这个宏实现了转换方法<b>DownCast</b>(),应该在<b>C</b>++文件中使用。
<b>DEFINE</b>_<b>STANDARD</b>_<b>RTTI</b>(<b>class</b>_<b>name</b>) 这个宏声明方法需要<b>RTTI</b>支持,应该在类的<b>public</b>中使用。
<b>IMPLEMENT</b>_<b>STANDARD</b>_<b>RTTIEXT</b>(<b>class</b>_<b>name</b>, <b>ancestor</b>_<b>name</b>) 实现上面的方法。
注:在使用这些宏的时候,必须确保参数的正确性,特别是父类的名字。否则定义将会不正确,且编译也不会报错。
三、内存管理 <b>Memory</b> <b>Management</b> <b>in</b> <b>Open</b> <b>CASCADE</b>
在几何建模的过程中,程序创建和删除相当数量的<b>C</b>++对象在动态内存中,也就是堆中(<b>heap</b>)。在这种情况下,标准函数管理内存的性能可能不足够。所以,<b>Open</b> <b>CASCADE</b>在标准包中实现了内存的管理。
3.1 用法 <b>Usage</b>
使用<b>Open</b> <b>CASCADE</b>内存管理只需要在<b>C</b>中使用<b>malloc</b>()的地方使用<b>Standard</b>::<b>Allocate</b>();在使用<b>free</b>()的地方使用<b>Standard</b>::<b>Free</b>();在使用<b>realloc</b>()的地方使用<b>Standard</b>::<b>Reallocate</b>()。
在<b>C</b>++中,类的操作符<b>new</b>()和<b>delete</b>()已经定义了在申请内存时使用<b>Standard</b>::<b>Allocate</b>()并在释放时使用<b>Standard</b>::<b>Free</b>()。所以,类所有的对象的内存都将由<b>Open</b> <b>CASCADE</b>的内存管理器来管理。
<b>CDL</b> <b>extractor</b>为所有的类定义了<b>new</b>()和<b>delete</b>()。所以,所有的<b>Open</b> <b>CASCADE</b>的类(小部分除外)都使用<b>Open</b> <b>CASCADE</b>的内存管理器。
由于操作符<b>new</b>()和<b>delete</b>()被继承,所以,所有从<b>Open</b> <b>CASCADE</b>派生的类,所有从<b>Standard</b>_<b>Transient</b>类派生的类都是由内存管理器管理。
注:若重载了部分从<b>Standard</b>_<b>Transient</b>类派生类的<b>new</b>()和<b>delete</b>(),尽管不推荐这样做,方法<b>Delete</b>()必须重定义,以便对这样的指针使用<b>delete</b>操作。这将确保合适的<b>delete</b>()函数将会被调用,即使是由手柄控制的对象。
3.2 配置内存管理器 <b>Configuring</b> <b>Memory</b> <b>Manager</b>
<b>Open</b> <b>CASCADE</b>内存管理器可以被配置以便对不同的内存区域使用不同的优化技术,或者根本不使用任何优化而直接使用<b>C</b>的<b>malloc</b>()和<b>free</b>()函数。配置方法为修改环境变量的值:
l <b>MMGT</b>_<b>OPT</b>:
l <b>MMGT</b>_<b>CLEAR</b>:
l <b>MMGT</b>_<b>CELLSIZE</b>:
l <b>MMGT</b>_<b>NBPAGES</b>:
l <b>MMGT</b>_<b>THRESHOLD</b>:
l <b>MMGT</b>_<b>REENTRANT</b>:
3.3 实现细节 <b>Implementation</b> <b>details</b>
本段内容请参考原文。
四、异常处理 <b>Exception</b> <b>Handling</b>
异常处理提供了一种从指定点转换到其他点的一种方法。一个方法可能会产生一个异常,将程序从正常执行处转换到捕捉异常处。<b>Open</b> <b>CASCADE</b>提供了异常类的层次,其基类是包<b>Standard</b>中的<b>Standard</b>_<b>Failure</b>。<b>CDL</b> <b>extractor</b>使用标准接口生成异常类。
<b>Open</b> <b>CASCADE</b>也提供将系统信号的转换成异常的支持,如数除0这样所有的情况都可以用安全、统一的方法来处理了。但是为了支持不同的平台,也使用了一些特殊的方法。
如下内容为在<b>Open</b> <b>CASCADE</b>中使用异常处理的推荐方法。
4.1 产生异常 <b>Raising</b> <b>an</b> <b>Exception</b>
类<b>C</b>++的语法:产生适当的异常将需要调用指定类型的<b>Raise</b>()方法。
产生了一个<b>DomainError</b>类型的异常并可附上相关信息“<b>Cannot</b> <b>cope</b> <b>with</b> <b>this</b> <b>condition</b>”,信息字符串是可选的。这个异常可以被捕捉<b>DomainError</b>类型的<b>Handler</b>捕捉到:
正常使用异常处理:异常不能被当作编程技巧来替代“<b>goto</b>”,但可作为防止方法被误用的一种方法。
五、<b>Plug</b>-<b>In</b>管理
六、结论
本章内容介绍了一些<b>C</b>++编程的知识及<b>Open</b> <b>CASCADE</b>对<b>C</b>++的包装。其中,手柄编程是<b>C</b>++中常见的方法,这种引用计数的方式使内存的管理更方便。
<a href="mailto:[email protected]"><b>eryar</b>@163.<b>com</b></a>
<b>Pudongxin</b> <b>Shanghai</b> <b>China</b>
<b>2012-8-23</b>