级别: 中级 Vinod V. Uddaraju (vinod.varma@in.ibm.com), 高级软件工程师, IBM Pratima Gangalavoi (pratima.g@in.ibm.com), 系统软件工程师, IBM
2008 年 7 月 11 日 本文是系列文章的第 2 部分,它对于当您在 IBM® Rational® Systems Developer 或者 IBM® Rational® Software Architect 中运行 UML 到 C++ 的转换时更好地控制所生成的 C++ 代码,提供了许多提示和帮助。除此之外,它还描述了如何从一个 UML 模型中生成虚拟的、内联的以及友好的函数。它还描述了如何控制用于模板类的代码生成,并且提供了使用 UML 到 C++ 转换的代码生成的许多其他方面的详细信息。
生成 C++ 虚函数
本小节将向您介绍如何从一个 UML 模型中创建 C++ 虚函数。为了在一个类中创建一个 C++ 纯虚函数,您需要在一个 UML 类的内部创建一个 UML 操作,并且确保该操作的 General Properties 中的 Abstract Qualifier 被选中。
举例来说,创建一个纯虚函数:virtual int purevirtualop(int x)=0,请执行如下这些操作:
- 创建一个名为
purevirtualop 的 UML 操作,其返回值类型为 int,参数 x 的类型为 int。
- 选中该操作的 Properties 标签中的 Abstract 和 Unique Qualifiers,如图 1 中所示。为纯虚函数所生成的代码如列表 1 中所示。
图 1. 为一个纯虚函数设置属性。
列表 1. 在头文件中为一个纯虚函数所生成的代码。
//@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)"
virtual int purevirtualop(int x)=0;
}; //end class Class1
|
为了在一个类中生成一个 C++ 虚函数,您需要在一个 UML 类的内部创建一个 UML 操作,并且将 cpp_operation 套用在该 UML 操作上面。这一套用具有三对属性/值:
- isFriend
- isInline
- isVirtual
属性 isVirtual 的默认值是 True。举例来说,要创建一个虚函数:virtual int virtualop(int x),请您执行下述步骤:
- 创建一个 UML 操作
virtualop,其返回值类型为 int,并且参数 x 的类型为 int。将 cpp_operation 套用到它的上面。
- 按照图 2 所示的内容设置该套用的属性:
- 将 isFriend 设置为
False;
- 将 isInline 设置为
False;
- 将 isVirtual 设置为
True。
- 运行 UML 到 C++ 的转换。在头文件中为该虚函数所生成的代码如列表 2 中所示。
图 2. 为一个虚函数设置属性。
列表 2. 在头文件中为一个虚函数所生成的代码。
//@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)"
virtual int virtualop(int x);
}; //end class Class1
|
生成 C++ 内联函数
本小节向您介绍如何从一个 UML 模型中创建 C++ 内联函数。为了在一个类中创建一个 C++ 内联函数,您需要在一个 UML 类的内部创建一个 UML 操作,并且将 cpp_operation 套用在该 UML 操作上面。属性 isInline 的默认值被设置为 True。
举例来说,要创建一个虚函数:inline int inlineop(int x),请您执行下述步骤:
- 创建一个 UML 操作
inlineop,其返回值类型为 int,并且参数 x 的类型为 int。
- 将
cpp_operation 套用到它的上面。
- 按照图 3 所示的内容设置该套用的属性:
- 将 isFriend 设置为
False;
- 将 isInline 设置为
True;
- 将 isVirtual 设置为
False。
图 3. 为一个内联函数设置属性。
UML 到 C++ 的转换为生成一个内联函数的代码生成提供了两个选项。默认的选项是在头文件和实体文件中都为内联函数生成代码。头文件中包含函数的声明,如列表 3 中所示,而实体文件中包含函数的定义,如列表 4 中所示。
列表 3. 在头文件中为一个内联函数所生成的代码。
//@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)"
inline int inlineop(int x);
}; //end class Class1
|
列表 4. 在实体文件中为一个内联函数所生成的代码。
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
int Class1::inlineop(int x)
{
//TODO Auto-generated method stub
return 0;
}
|
该转换还提供了另外一个选项:为一个在类声明下的头文件中的内联函数生成该函数的定义。要激活这一选项,请您执行下述步骤:
- 将
-DINLINE_HEADER=true VM 参数添加到 eclipse.ini 文件后面。
- 接下来,重新启动 Rational System Developer 或者 Rational Software Architect,采用
-clean 选项。
- 另外,您也可以重新启动 Rational System Developer 或者 Rational Software Architect,在命令行中执行选项:
-vmargs -DINLINE_HEADER=true。
采用这一选项为内联函数所生成的声明和定义将全部位于头文件中,如列表 5 所示。
列表 5. 使用
DINLINE_HEADER
选项为一个内联函数生成代码。
//@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)"
inline int inlineop(int x);
}; //end class Class1
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
int Class1::inlineop(int x)
{
//TODO Auto-generated method stub
return 0;
}
|
生成 C++ 友函数
本小节将向您介绍如何从一个 UML 模型中创建 C++ 友函数。为了在一个类中创建一个 C++ 友函数,您需要在一个 UML 类的内部创建一个 UML 操作,并且将 cpp_operation 套用在该 UML 操作上面。属性 isFriend 的默认值被设置为 True。
要创建一个友函数:friend int Class2::friendop (int x),同时该函数的友好性被定义在 Class2 中,请您执行下述步骤:
- 创建一个
Class2::friendop 操作,其返回值类型为 int,并且参数 x 的类型为 int。
- 将
cpp_operation 套用到它的上面。
- 按照图 4 所示的内容设置该套用的属性:
- 将 isFriend 设置为
True;
- 将 isInline 设置为
False;
- 将 isVirtual 设置为
False。
生成的代码如列表 6 中所示。
图 4. 为一个友函数设置属性。
列表 6. 为一个友函数生成代码。
//@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)"
friend int Class2::friendop(int x);
}; //end class Class1
|
建模一个模板类
本小节讨论在一个 UML 模型中建模一个 C++ 模板类。为了建模一个 C++ 模板类,您需要首先创建一个 UML 类,然后向其中添加类型为 Class(或者任何一种 UML 基本类型)的模板参数。
要创建一个模板类,例如:template class one<class T, int X> {int op(){}};,首先创建一个 UML 类,然后添加下面两个模板参数和一个 UML 操作:
- 如图 5 中所示的类类型(命名为 T)的模板参数,右键单击 source > Models > one 并且选择 Add UML > Template Parameter > Class。
- 如图 6 中所示整数类型(命名为 X)的模板参数,右键单击 source > Models > one 并且选择 Add UML > Template Parameter > Integer。
- 一个 UML 操作,并且以一个
int 作为返回值类型。
图 5. 创建一个类类型的模板参数。
图 6. 创建一个整数类型的模板参数。
为模板类一所生成的代码具有在模板类声明内部用于操作的声明和定义,如列表 7 中所示。这是版本 7.0.0.3 及其后续版本中所具备的。
列表 7. 为一个模板类所生成的代码。
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
template <class T, int X>
class one
{
//Begin section for one
//TODO: Add attributes that you want preserved
//End section for one
public:
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
int op()
{
//TODO Auto-generated method stub
return 0;
}
}; //end class one
|
该转换还提供了一个选项来为类类型的模板参数生成替换 class 的关键字。
- 为了激活这一选项,您需要将 VM 参数
-DTYPENAME_TEMPLATES=true 添加到 eclipse.ini 文件后面。
- 接下来,重新启动 Rational System Developer 或者 Rational Software Architect,并且采用
-clean 选项。
- 另一个选项是,您可以重新启动 Rational System Developer 或者 Rational Software Architect,并且采用命令行选项
-vmargs -DTYPENAME_TEMPLATES=true。通过这一选项,关键字 typename 被生成用来类类型的每一个模板参数。采用这一选项所生成的代码如列表 8 中所示。
列表 8. 为一个采用 DTYPENAME_TEMPLATES 选项的模板类所生成的代码。
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
template <typename T, int X>
class one
{
//Begin section for one
//TODO: Add attributes that you want preserved
//End section for one
public:
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
int op()
{
//TODO Auto-generated method stub
return 0;
}
}; //end class one
|
为头文件和实体文件创建不同的扩展
这一小节负责为生成的和一个 UML 类相对应的头文件和源文件创建不同的文件扩展名。为了为和一个 UML 类相对应的头文件和源文件创建不同的文件扩展名,请您将 cpp_properties 套用到该 UML 类上面。这一套用具有两个属性:
-
headerFileExtension:这一属性被用来设置头文件的扩展名。
-
bodyFileExtension:这一属性被用来设置实体文件的扩展名。
在一个扩展名为 .inc 的头文件和一个扩展名为 .in 的源文件中为一个 UML 类生成代码,请您执行如下步骤:
- 创建一个 UML 类 class1,并且向其添加一个操作
op,其返回值类型为 int。
- 将
cpp_properties 套用到 UML 类上面,并且设置 headerFileExtension 属性为 .inc,设置 bodyFileExtension 属性为 .in,如图 7 中所示。
图 7. 为不同的头文件和实体文件扩展设置属性。
生成的代码中将包括文件 class1.inc 和 class1.in。这些文件的扩展名(.inc 和 .in)需要被关联到 C++ 头文件和源文件,从而 C/C++ development 套件能够将 .inc 和 .in 识别为有效的 C++ 文件扩展名。为了达到这一目的,请您执行下述步骤:
- 进入 Window > Preferences > General > Editors > File Associations。
- 点击位于页面顶部的 Content Types 链接。
- 定位到 Text > C Source File > C++ Source File > C++ Header File。
- 点击 Add,如图 8 中所示的对话框将会显示出来。
- 在这个对话框中,将扩展类型指定为
*.inc,并且点击 OK。
图 8. 为头文件设置扩展。
- 向下滚动到文件关系小节,确认 *.inc 已经作为一个用于 C++ 头文件的文件关系被包括进来,如图 9 中所示。
- 点击 OK。此处,在 C++ 项目中任何一个扩展名为 .inc 的文件都被 C/C++ 开发套件认为是一个 C++ 头文件。
图 9. 用于 C++ 头文件的文件联系。
- 定位到 Text > C Source File > C++ Source File。
- 点击 Add,如图 10 中所示的对话框就会显示出来。
- 在这个对话框中,将扩展类型指定为
*.in,并且点击 OK。
图 10. 为源文件设置扩展。
- 向下滚动到文件关系小节,确认
*.in 已经作为一个用于 C++ 源文件的文件关系被包括进来,如图 11 中所示。
- 点击 OK。此处,在 C++ 项目中任何一个扩展名为 .in 的文件都被 C/C++ 开发套件认为是一个 C++ 源文件。
图 11. 用于 C++ 源文件的文件联系。
控制一个类内部的可见性顺序
生成代码在默认情况下是根据可见性进行排序的。默认的顺序为 private(私有的)、protected(受保护的)和 public(公共的)。这意味着类元素的所有的私有成员都将被首先转储,然后依次是被保护的成员和公共的成员。为了观察生成的代码,请您创建一个 UML 模型,然后添加一个 UML 类 A。向这个类中添加以下这些元素:
- 一个 UML 属性 a (类型为
int)和一个 UML 操作 abc (返回值类型为 void)。将这两个元素的可见性设置为 private。
- 一个 UML 属性 b (类型为
int)和一个 UML 操作 xyz (返回值类型为 int)。将这两个元素的可见性设置为 protected。
- 一个 UML 属性 c (类型为
int)和一个 UML 操作 pqr (返回值类型为 bool)。将这两个元素的可见性设置为 public。
为这一 UML 模型所生成的代码如列表 9 中所示。
列表 9. 根据可见性顺序排列所生成的代码。
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
class A
{
//Begin section for A
//TODO: Add attributes that you want preserved
//End section for A
private:
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
int a;
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
void abc();
protected:
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
int b;
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
int xyz();
public:
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
int c;
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
bool pqr();
}; //end class A
|
UML 到 C++ 的转换提供了一个以公共元素、被保护元素、私有元素这一顺序生成代码的选项。
- 为了激活这一选项,请您将
-DVISIBILITY_ORDER=true VM 参数添加到 eclipse.ini 文件中。
- 接下来,重新启动 Rational System Developer 或者 Rational Software Architect,并且采用
-clean 选项。
- 另外,您还可以重新启动 Rational System Developer 或者 Rational Software Architect,并且采用命令行选项
-vmargs -DVISIBILITY_ORDER=true 。采用这一选项生成的代码如列表 10 中所示。
列表 10. 采用 DVISIBILITY_ORDER 选项的代码生成。
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
class A
{
//Begin section for A
//TODO: Add attributes that you want preserved
//End section for A
public:
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
int c;
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
bool pqr();
protected:
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
int b;
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
int xyz();
private:
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
int a;
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
void abc();
}; //end class A
|
UML 到 C++ 的转换还提供一个以和它们在 UML 模型中被储存的相同顺序生成类属性和操作的选项。
- 要选中这一选项,请您定位到 Window > Preferences > Modeling > Transformations > UML to C++ Transformation。
- 选择 Edit Styles 页面。
- 在这一页面中,选中 Sort By storage 选项,如图 12 中所示。采用这一选项生成的代码如列表 11 中所示。
图 12. 根据 Storage 选项设置排列顺序。
列表 11. 采用 DVISIBILITY_ORDER 选项的代码生成。
//@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
private:
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
int a;
protected:
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
int b;
public:
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
int c;
private:
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
void abc();
protected:
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
int xyz();
public:
//@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)"
bool pqr();
}; //end class Class1
|
将 Exclude Path 用于 Include 选项
从 UML 模型的代码中所生成的 #include 声明具有到达被包含文件的相对路径。举例来说,考虑一个具有两个类(Class1 和 Class2)之间依赖的 UML 模型,每一个都嵌套在一个不同的包中(Package1 and Package2)。在这种情况下,在 Class1.h 中所生成的代码如列表 12 中所示。请注意相对路径“../Package2/Class2.h”被生成到头文件中(Class2.h)。
列表 12. 为 #include 所生成的代码。
#include "../Package2/Class2.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
};
|
UML 到 C++ 的转换提供了一个生成只包含相应被包含文件的文件名的 #include 声明的选项。要激活这一选项,请访问 UML 到 C++ 转换配置向导的属性页面,并且选择 Suppress path names in include directives 选项,如图 13 中所示。
在 Rational Software Architect 和 Rational System Developer 的版本 7.0.5 以及后续的版本中,提供了 Suppress path names in include directives 选项。采用这一选项所生成的代码(从上面所提到的 UML 模型中)如列表 13 中所示。请注意只有文件名 Class2.h 是被生成的。
图 13. 设置“Suppress path names in include directives option”
列表 13. 采用 DEXCLUDE_PATH_FOR_INCLUDES 选项为 #include 所生成的代码。
#include "Class2.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
};
|
您所学习的内容以及下一步的展望
在本文中,您学习了如何完成以下操作:
- 生成 C++ 虚函数;
- 生成 C++ 内联函数;
- 生成 C++ 友函数;
- 建模一个模板类;
- 为头文件和实体文件创建不同的扩展;
- 控制一个类内部的可见性顺序;
- 将 Exclude Path 用于 Include 选项;
在 第 3 部分 中,您将学习如何在 UML 中建造 C++ 特定模型,进而生成代码。
参考资料 学习
获得产品和技术
讨论
作者简介  | |  | Vinod Varma 在过去的三年中一直从事于 IBM Rational 建模工具的开发工作。他担当过许多不同的建模工具的工作,如 Rational Rose,Rational Software Architect,以及 Rational System Developer。 |
 | 
|  | Pratima Gangalavoi 是工作在 Rational Software Architect 和 Rational Systems Developer 上的一名系统软件工程师,在 IBM Rational Software Bangalore 实验室工作。她主要工作于这些工具的 C++ 转换。 |
对本文的评价
|