使用Rational进行C++转换的技巧

  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 概要文件
  
使用Rational进行C++转换的技巧

  如图2所示,从 Deployed Profile 下拉列表框中选择 C++ Transformation。
  图2. 选择 C++ Transformation
  
使用Rational进行C++转换的技巧

  导入 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++ 类型库
  
使用Rational进行C++转换的技巧

  如图4所示,从 Deployed Library 列表中选择 C++ Types。
  图4. 导入 C++ Type Library
  
使用Rational进行C++转换的技巧

  在模型中创建 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++ 类型定义
  
使用Rational进行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. 创建一个常量方法
  
使用Rational进行C++转换的技巧

  给一个方法增加异常处理
  Exceptions 是 UML 中重要的类,它在建模过程中不需要使用概要文件。为了简化并推广建模, UML to C++ Transformation 使用了普遍适用的 UML 属性,而不是概要文件。要生成一个 throw 子句,比如 int Operation1() throw ( MyType);,您首先需要为操作创建一个参数,然后设置其 Is Exception 属性为 true。
  在转换过程中,参数名是可以被忽略的,但最好还是定义一个合适的名称(以备异常抛出时正确提示)。图8显示了如何将参数的 Is Exception 属性设置为 true。
  图8. 设置某方法的 throw 类型
  
使用Rational进行C++转换的技巧

  控制生成的代码中的 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. 使用映射模型
  
使用Rational进行C++转换的技巧

  单击 New 按钮,创建一个默认的映射模型,赋给一个适合的名称。单击 Edit Mapping 按钮,出现如图10所示的对话框。
  图10. 编辑映射模型
  
使用Rational进行C++转换的技巧

  假使您正进行到如图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 类映射为另外命名的文件。类的名称并不受映射模型的影响。因此,要想在一个文件中生成多个类,您所需要做的仅仅是在映射模型中为它们指定相同的目标名称。