C / C ++函数指针的UML表示
在UML结构图中,C / C ++函数指针(fp)的最佳表示是什么?
我正在考虑使用一个接口元素,即使是“退化”,但最多只能声明一个操作。
我在本文档中找到了一些建议: C和UML同步用户指南,第5.7.4节 。 但这听起来很麻烦,在实践中不是很有用。 即使从非常低级别的语义视图来看也是如此。 这是一个简要显示其概念的图表:
C和C ++函数指针中的恕我直言被用作界面的狭窄视图,该视图仅提供单个函数及其签名。 在C fp中,它还将用于实现更复杂的接口,声明包含一组函数指针的结构。
我想我甚至可以设法让我的特定UML工具(Enterprise Architect)转发生成正确的代码,并与代码更改同步而不会造成伤害。
我的问题是:
- 声明fp作为UML中界面元素的一部分会提供正确的语义视图吗?
- 单个fp声明应该使用什么样的刻板印象? 至少我需要在代码中提供一个typedef,
所以这将是我的胆量选择。(我发现这个构造型是Enterprise Architect专有的)我需要定义一个合适的构造型来使代码生成适应。 实际上我选择了刻板印象的名称’委托’,这是否有任何影响或语义冲突? - 至于C ++,是否会在类元素中嵌套一个’委托’的类型化接口,足以正确表达一个类成员函数指针?
这是我对C语言表示的想法示例图:
这是应该从上面的模型生成的C代码:
struct Interface1; typedef int (*CallbackFunc)(struct Interface1*); typedef struct Interface1 { typedef void (*func1Ptr)(struct Interface1*, int, char*); typedef int (*func2Ptr)(struct Interface1*, char*); typedef int (*func3Ptr)(struct Interface1*, CallbackFunc); func1Ptr func1; func2Ptr func2; func3Ptr func3; void* instance; }; /* The following extern declarations are only dummies to satisfy code * reverse engineering, and never should be called. */ extern void func1(struct Interface1* self, int p1, char* p2) = 0; extern int func2(struct Interface1* self, char*) = 0; extern int func3(struct Interface1* self, CallbackFunc p1) = 0;
编辑:
整个问题归结为手头的UML工具及其特定代码工程function的最佳方式。 因此,我添加了企业架构师标签。
关于函数指针的主题,EA的帮助文件有如下说明:
导入C ++源代码时,Enterprise Architect会忽略函数指针声明。 要将它们导入模型,您可以创建一个typedef来定义函数指针类型,然后使用该类型声明函数指针。 以这种方式声明的函数指针将作为函数指针类型的属性导入。
注意“可以。” 这是来自C ++部分,C部分根本没有提到函数指针。 所以它们得不到很好的支持,而这当然是由于建模和编程社区之间的差距:UML中根本不支持非平凡的语言概念,因此任何解决方案都必须是特定于工具的。
我的建议有点牵扯,它有点hacky,但我认为它应该工作得很好。
因为在UML操作中不是第一类并且不能用作数据类型,我的响应是为它们创建第一类实体 – 换句话说,将函数指针类型定义为类。
这些类有两个目的:类名将反映函数的类型签名,以使程序员在图中看起来很熟悉,而一组标记值将代表用于代码生成的实际参数和返回类型。
0)您可能需要为步骤1-4设置MDG技术。
1)使用Detail“Type = RefGUID; Values = Class;”定义标记值类型“retval”。
2)使用名为“par1”,“par2”的相同Detail定义另一组标记值类型,依此类推。
3)使用包含“retval”标记值(但没有“par”标记)的类构造型“funptr”定义一个配置文件。
4)修改代码生成脚本属性声明和参数以检索“retval”(始终)和“par1” – “parN”(定义的位置)并为它们生成正确的语法。 这将是棘手的一点,我实际上没有这样做。 我认为可以毫不费力地完成,但你必须尝试一下。 您还应该确保没有为“funptr”类定义生成代码,因为它们代表匿名类型,而不是typedef。
5)在目标项目中,定义一组类来表示原始C类型。
有了这个,你可以将一个函数指针类型定义为一个名为“long(*)(char)”的«funptr»类,用于获取char并返回long的函数。
在“retval”标签中,选择您在步骤4中定义的“long”类。
手动添加“par1”标记,并选择上面的“char”类。
您现在可以将此类用作属性或参数的类型,或EA允许类引用的任何其他位置(例如,在其他«funptr»类的“par1”标记中;这使您可以轻松地创建指针类型函数,其中一个参数本身就是函数指针类型)。
这里最讨厌的是编号为“par1” – “parN”的标签。 虽然在EA中可以定义几个具有相同名称的标签(您可能需要更改标记值窗口选项以查看它们),但我认为您不能在代码生成脚本中检索不同的值(即使你可以不认为订单必须保留,参数顺序在C)中很重要。 因此,您需要事先确定最大参数数量。 在实践中不是一个大问题; 设置说20个参数应该是充足的。
此方法对逆向工程没有帮助,因为EA 9不允许您自定义逆向工程过程。 然而,即将到来的EA 10(目前在RC 1中)将允许这一点,虽然我自己没有看过它,所以我不知道这将采取什么forms。
定义函数指针超出了UML规范的范围。 更重要的是,它是许多UML建模软件不支持的特定于语言的function。 因此,我认为对您的第一个问题的一般答案建议避免使用此function。 您提供的技巧仅与Enterprise Architect相关,并且与其他UML建模工具不兼容。 以下是其他一些UML软件支持函数指针的方法:
MagicDraw UML对FP类成员使用<< C++FunctionPtr
>>构造型,对函数原型使用<< C++FunctionPtr
>>。
代码示例(取自官方网站 – 请参阅“用于C ++代码生成的建模typedef和函数指针”视图):
class Pointer { void (f*) ( int i ); }
对应的UML模型:
Objecteering使用相应的C ++ TypeExpr注释定义FP属性。
IBM的Rational Software Architect不支持函数指针。 用户可以将它们添加到用户定义的部分中生成的代码中,这些部分在代码 – > UML和UML->代码转换期间保持不变。
对我来说似乎是对的。 我不确定你应该深入了解描述单个函数指针的类型和关系的底层细节。 我通常发现描述界面足够分离而不需要分解它的内部元素。
我认为你可以用一个类来实际包装函数指针。 我认为UML不是代码的蓝图级别,记录概念更重要。
我的感觉是你希望将UML接口映射到struct-with-function-pointers C idiom。
Interface1是模型中的重要元素。 在整个地方声明函数指针对象类型将使您的图表难以辨认。
Enterprise Architect允许您指定自己的代码生成器。 寻找代码模板框架 。 您应该能够借助一两个新的构造型修改C的预先存在的代码生成器。
就像你的第一个例子一样,我会使用一个分类器,但将它隐藏在一个配置文件中。 我认为他们已将其包括在内以便清楚地解释这个概念; 但在实践中,刻板印象的整个想法是抽象的细节,以避免“噪音”问题。 EA非常适合处理Profiles。
我与第一个例子的不同之处在于,我将对原始 类型的原型进行分类,而不是对数据类型的原型进行分类。 数据类型是域范围对象,而原始类型是primefaces元素,其语义在UML范围之外定义。 这并不是说你不能添加注释,特别是在配置文件中或给它一个非常清晰的构造型名称,如functionPointer。
我已经能够与Enterprise Architect合作。 它有点像hacky解决方案,但它符合我的需求。 我做了什么:
-
创建一个名为FuncPtr的新类构造型。 我按照指南进行了访问: http : //www.sparxsystems.com/enterprise_architect_user_guide/10/extending_uml_models/addingelementsandmetaclass.html当我这样做时,我为该配置文件创建了一个新视图。 所以我可以将它保存在我的主项目之外。
-
修改了类代码模板。 基本上选择C语言并从类模板开始并点击“添加新的原型覆盖”并添加FuncPtr作为新的覆盖。
-
将以下代码添加到该新模板:
%PI="\n"% %ClassNotes% typedef %classTag:"returnType"% (*%className%)( %list="Attribute" @separator=",\n" @indent=" "% );
-
修改了属性声明代码模板。 与以前一样,添加一个新的Stereotype
-
将以下代码添加到新模板中:
%PI =“”%% attConst ==“T”? “const”:“”%
%attType%
%attContainment ==“参考”? “*”:“”%
%attName%
这就是我必须要做的就是在Enterprise Architect中获得函数指针。 当我想定义一个函数指针时我只是:
- 创建一个常规类
- 在标签’returnType’中添加我想要的返回类型
- 添加参数的属性。
这样它就会创建一个新类型,可以作为属性或参数包含在其他类(结构)和运算符中。 我没有把它变成一个操作符本身,因为它不会在工具中引用作为你可以选择的类型。
所以它有点hacky,使用特殊的构造类作为typedef来实现指针。