【 tulaoshi.com - 编程语言 】
UML 是一个通用的语言。使用 IBM? Rational Software Architect 和 IBM Rational Systems Developer,您可以实现由 UML 模型向 C++ 的转换。这篇文章讨论了如何更好地控制由 UML 向 C++ 转换而生成的 C++ 代码。文章分成几个章节,各部分相对独立,分别介绍了一种技巧。您可以根据需要选读,而不必遵循特定的次序。
应用 C++ Transformation 概要文件以实现 C++ 结构的建模 在统一建模语言 UML 和某特定领域之间建立联系的标准方法是使用 UML Profile(UML 概要文件)。UML 概要文件可以为已有 UML 元素定义附加语义和特性,例如类、操作等。建模 C++ 特定元素的时候,如 结构体、联合体、名字空间 等,需要用到 UML 概要文件。在 Rational Software Architect 和 Rational Systems Developer 使用 C++ Transformation profile 实现 UML 向 C++ 的转换,这个概要文件在 UML 模型中的应用如下所示。
在 Project EXPlorer 中选择概要文件将要应用的 UML 模型。
在 Project Explorer 保持模型是选中状态,转换到 Properties View,单击 Profiles 选项卡。
如图1所示,单击 Add Profile 按钮。
图1. 将 UML 运用到 C++ Transformation 概要文件
如图2所示,从 Deployed Profile 下拉列表框中选择 C++ Transformation。
图2. 选择 C++ Transformation
导入 C++ 类型库 UML 提供了一组已定义好的类型,有 Boolean, Integer, String 和 UnlimitedNatural。而大多数的编程语言,包括C++,提供了更为丰富的基本类型。在 C++ 中建模的时候,您可能经常需要使用 C++ 预定义的原始类型(比如,将一个类型赋给某个属性、参数、操作返回类型,等)。To import the C++ model library that is shipped with the C++ Transform,在 Project Explorer 中右键单击UML模型,然后选择 Import Model Library,如下图3所示。
图3. 导入 C++ 类型库
如图4所示,从 Deployed Library 列表中选择 C++ Types。
图4. 导入 C++ Type Library
在模型中创建 C++ 名字空间 本章节讲述如何在 UML 模型中为 C++ 名字空间建模。在 C++ 中创建一个名字空间时,需要将 cpp_namespace 原型应用在 UML 包。在 UML 向 C++ 转换的过程中,一个 UML 包默认被映射成一个文件夹。假如想要将 UML 包映射成名字空间,而不是文件夹,那么,您需要应用 cpp_namespace 原型,然后设置 NamespaceName 的属性,使其与指定的名字空间相关联。这个 stereotyped UML 包下所有的 类、结构、枚举 (以及其它)生成代码之后,都将包括在这个名字空间中。
您可能想知道为什么名字空间不能直接采用 stereotyped 包的名称。这是为了支持 C++ 匿名的名字空间建模。所以,假如您将 NamespaceName 属性设置为空,那么,该名字空间就会被认为是匿名的。
建模 C++ typedefs 要建模 C++ typedef,需要创建一个 UML 类并在其上应用 cpp_typdef 原型。该原型提供了以下属性/值:
arrayDimensions
ImplementationType
qualifier
想要创建一个类型定义,比如 typedef int const IntMatrix100_20_t [10][20];,首先创建一个 UML 类 IntMatrix100_20_t,然后应用 cpp_typedef 原型。如图5所示,设置该原型的属性。
图5. 建立一个 C++ 类型定义
在将 typedef 定义与概要文件中提供的属性相关联的过程中,您可能会考虑到以下方式: typedef
创建多维数组属性
在本节中,您将会学到如何为一个大小为[10][20][30]的三维数组定义属性。在 Project Explorer 中选择需要赋给多维数组的属性。在 Properties 视图中,单击 Stereotypes 选项卡,然后单击 Apply Stereotypes 按钮,并选择 cpp_type 原型。这个原型提供了以下属性/值:
arrayDimensions
InitializerKind
isAuto
isMutable
isRegister
isVolatile
qualifier
如图6所示,在 arrayDimensions Value 处,指定 [10][20][30]。这样,在源代码中就会生成维度属性为[10][20][30]的数组。
图6. 设置 Multidimensional Attributes
将一个方法的形参设置为常量
这个技巧的原理同上(前面提到的定义多维数组)。在 Project Explorer 中选择预备设置为 const 的参数。单击 Apply Stereotypes 按钮并选择 cpp_type 原型。该类型提供了以下属性/值:
arrayDimensions
InitializerKind
isAuto
isMutable
isRegister
isVolatile
qualifier
这些属性都是可能用得到的,但暂时只介绍 qualifier 属性。在 qualifier 的 Value 处,输入 const (如 图5 所示)。这样,当转换执行的时候,将在源代码中为选定的参数生成带有常量修饰符的函数签名。
注: 请确保输入的值是有效的。假如输入错误,则会导致编译失败,您需要在再次运行转换之前修正错误。
另外,cpp_type 原型也适用于类的属性。但是,生成一个常量属性的更简单的方法是将属性标明为 Read Only。
将整个方法声明为常量
假设您想要将一个方法声明为常量,以便在生成的代码中带有 const 要害字: )int Operation1(MyType Parameter1 const;。您需要在 Properties 视图的 General 选项卡中选择 Query 修饰符。这里,不需要应用原型。
图7. 创建一个常量方法
给一个方法增加异常处理
Exceptions 是 UML 中重要的类,它在建模过程中不需要使用概要文件。为了简化并推广建模, UML to C++ Transformation 使用了普遍适用的 UML 属性,而不是概要文件。要生成一个 throw 子句,比如 int Operation1() throw ( MyType);,您首先需要为操作创建一个参数,然后设置其 Is Exception 属性为 true。
在转换过程中,参数名是可以被忽略的,但最好还是定义一个合适的名称(以备异常抛出时正确提示)。图8显示了如何将参数的 Is Exception 属性设置为 true。
图8. 设置某方法的 throw 类型
控制生成的代码中的 include 声明
UML to C++ Transformation 可以自动生成恰当的 include 声明。 然而,您可能想要根据需要生成更合适的 include 声明。例如,已确定要使用本地方法体的某个类型变量,因此,想要生成包括在文件中的 include 声明建模时,您可能需要创建两个类之间的依靠,然后将 cpp_dependency 原型应用在依靠。这个原型和名为 IsInclusionInHeader 的属性一起出现,该属性值默认为 false。假如需要将 include 声明包括在生成的文件体中,请将这个属性值设为 false;假如需要将 include 声明生成在头文件中,那么,可以不设置依靠的 cpp_dependency 原型,也可以应用原型并将 IsInclusionInHeader 属性值设为 true。
使用文件级别得重用保护部分
假如要使用标准库的类型,或者一些源代码的其它库,您需要在模型中将这些类型设置为普通的字符串。例如,假如要将一个属性声明为整型,您需要在模型中指定它的类型为 vector 转换时,将会把这些类型当成原始类型,并且不会生成任何 include 声明或其它声明。因此,您需要将这些都明确地包含进源文件中。
比如,对于 vector 类型,您应当明确地将 include 声明放置在源代码中,比如 #include 。如列表1所示,在应用 UML 向 C++ 的转换过程中,每个生成的文件都一字不漏地包含一些段落的内容。请注重 //TODO: Add definitions that you want preserved。您添加到 Begin section 和 End section 中的任何内容都将被保存下来。请在此处添加声明,比如这里的 #include 。
列表1. 类 Car 所生成代码
#ifndef CLASS1_H
#define CLASS1_H
//Begin section for file Class1.h
//TODO: Add definitions that you want preserved
//End section for file Class1.h
#include "MyType.h"
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
class Class1
{
//Begin section for Class1
//TODO: Add attributes that you want preserved
//End section for Class1
public:
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
int Operation1()const throw ( MyType);
}; //end Class Class1
#endif
删除类级别得重用保护部分
请注重,在前面列表1的代码中,有一段 //Begin section for Class1 ... //End section for Class1 ,您可以将 C++ 中所有不能建模的声明保存在这里。返回 UML to C++ Transformation 时,不会覆盖这段声明。假如您不需要这一声明出现在生成的代码中,可以选择删除。但是,删除之后,即使再次运行 UML to C++ Transformation,这些声明也不会重新生成。
假如不需要,可以删除如列表2所示的段落,那么删除之后不能够重新生成。假使想要恢复这些声明,您就需要手动地进行插入。
列表2. 类 Car 生成的代码
...
//Begin section for Class1
//TODO: Add attributes that you want preserved
//End section for Class1
...
不修改 UML 模型的情况下,改变生成包的名称。
要改变包的名称,请双击打开转换配置文件。如图9所示,单击 Mapping 选项卡,选择 Enable mapping。
图9. 使用映射模型
单击 New 按钮,创建一个默认的映射模型,赋给一个适合的名称。单击 Edit Mapping 按钮,出现如图10所示的对话框。
图10. 编辑映射模型
假使您正进行到如图11所示的 UML 模型。假如没有映射模型,那么 Date 类将会生成在一个名为 Package1 的文件夹内。然而,假如您想要将 Package1 生成为 Folder1,那么需要使用映射模型。浏览映射模型,找到 Package1,然后在向导底端的 Mapped Name 编辑框输入 Folder1。这样,在生成的代码中,Date 类就生成在名为 Folder1 的文件夹内了。
图11. 您正在操作的 UML 模型
在同一个文件里生成多个类
在映射模型中,假如您想将一个 UML 类映射为另外的名称,您需要改变其将要生成文件的名称,而不是类名。默认情况下,顶级类将生成一个与类名相同名称的文件。因此,对于一个名为 MyClass 的 UML 类,UML 向 C++ 的转换将会生成文件 MyClass.h 和 MyClass.cpp。
但是,在使用映射模型的时候,您也可以选择生成与原类名不同名称的文件。比如,您可以改变 UML 包的名称,生成另外命名的文件夹;您也可以将一个 UML 类映射为另外命名的文件。类的名称并不受映射模型的影响。因此,要想在一个文件中生成多个类,您所需要做的仅仅是在映射模型中为它们指定相同的目标名称。