17

UML構造図でのC/C ++関数ポインター(fp)の最良の表現は何でしょうか?

私はインターフェース要素を使用することを考えています。たとえ「縮退」したとしても、多くても1つの操作を宣言するという制約があります。

このドキュメントでいくつかの提案を見つけました:CおよびUML同期ユーザーガイド、セクション5.7.4。しかし、これは非常に面倒で、実際にはあまり役に立ちません。たとえ非常に低いレベルのセマンティックビューからでも。これが彼らの概念を簡単に示す図です: ここに画像の説明を入力してください

CおよびC++関数ポインターのIMHOは、単一の関数とその署名のみを提供するインターフェースのそのような狭められたビューとして使用されます。Cでは、fpは、関数ポインタのセットを含む構造体を宣言するより複雑なインターフェイスを実装するためにも使用されます。

特定のUMLツール(Enterprise Architect)で正しいコードを転送生成し、コードの変更と同期することで、害を及ぼすことなく管理できると思います。

私の質問は次のとおりです。

  1. UMLのインターフェース要素の一部としてのfpの宣言は、正しいセマンティックビューを提供しますか?
  2. シングルfp宣言にはどのようなステレオタイプを使用する必要がありますか?少なくとも、コードでtypedefを提供する必要があるので、これが私の根性の選択になります。(このステレオタイプはEnterprise Architect独自のものであることがわかりました)。コード生成を適応させるには、適切なステレオタイプを定義する必要があります。実際、私はステレオタイプ名「デリゲート」を選択しましたが、これには意味や意味の衝突がありますか?
  3. C ++の場合、クラスメンバー関数ポインターを正しく表現するのに十分なクラス要素に「デリゲート」ステレオタイプ化されたインターフェイスをネストしますか?

これは、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ツールとその特定のコードエンジニアリング機能を使用した場合の最善の方法を要約したものです。タグを追加しました。

4

7 に答える 7

10

EAのヘルプファイルには、関数ポインタについて次のように書かれています。

C ++ソースコードをインポートする場合、EnterpriseArchitectは関数ポインタ宣言を無視します。それらをモデルにインポートするには、typedefを作成して関数ポインター型を定義し、その型を使用して関数ポインターを宣言します。このように宣言された関数ポインタは、関数ポインタ型の属性としてインポートされます。

「できた」ことに注意してください。これはC++セクションからのものであり、Cセクションでは関数ポインターについてはまったく触れていません。したがって、これらは十分にサポートされていません。これはもちろん、モデリングコミュニティとプログラミングコミュニティの間のギャップが原因です。重要な言語の概念はUMLでサポートされていないため、ソリューションは必然的にツール固有になります。

私の提案は少し複雑で少しハッキーですが、かなりうまくいくはずだと思います。

UML操作はファーストクラスではなく、データ型として使用できないため、私の応答は、それらのファーストクラスエンティティを作成することです。つまり、関数ポインタ型をクラスとして定義します。

これらのクラスは2つの目的を果たします。クラス名は関数の型シグネチャを反映して、ダイアグラムでプログラマーにわかりやすくします。一方、タグ付きの値のセットは、コード生成で使用する実際のパラメーターと戻り値の型を表します。

0)ステップ1〜4のMDGテクノロジーを設定することをお勧めします。

1)詳細「Type = RefGUID; Values=Class;」を使用してタグ付き値タイプ「retval」を定義します。

2)「par1」、「par2」などの名前の同じ詳細を持つタグ付き値タイプのセットをさらに定義します。

3)「retval」タグ付きの値を含む(「par」タグを含まない)クラスステレオタイプ「funptr」でプロファイルを定義します。

4)コード生成スクリプトの属性宣言とパラメーターを変更して、「retval」(常に)と「par1」-「parN」(定義されている場合)を取得し、それらの正しい構文を生成します。これはトリッキーなビットになりますが、私は実際にはこれを行っていません。手間をかけずにできると思いますが、やってみる必要があります。また、「funptr」クラス定義はtypedefではなく匿名型を表すため、コードが生成されないようにする必要があります。

5)ターゲットプロジェクトで、プリミティブCタイプを表すクラスのセットを定義します。

これにより、関数ポインタ型を、charを受け取り、longを返す関数の「long(*)(char)」のような名前の«funptr»クラスとして定義できます。

「retval」タグで、手順4で定義した「long」クラスを選択します。

「par1」タグを手動で追加し、上記のように「char」クラスを選択します。

これで、このクラスを属性またはパラメーターのタイプとして、またはEAがクラス参照を許可する他の場所(別の«funptr»クラスの "par1"タグなど)で使用できます。これにより、パラメータの1つがそれ自体が関数ポインタ型である関数)。

ここで最もハッキーなビットは、番号が付けられた「par1」-「parN」タグです。EAでは同じ名前の複数のタグを定義することは可能ですが(タグ付けされた値ウィンドウのオプションを変更して表示する必要がある場合があります)、コード生成スクリプトで異なる値を取得することはできないと思います(順序が必ずしも保持されるとは思わないかもしれません。C)ではパラメーターの順序が重要です。したがって、パラメータの最大数を事前に決定する必要があります。実際には大きな問題ではありません。たとえば、20個のパラメータを設定するだけで十分です。

EA 9ではリバースエンジニアリングプロセスをカスタマイズできないため、この方法はリバースエンジニアリングには役立ちません。ただし、今後のEA 10(現在はRC 1)でこれが可能になりますが、私自身は調べていないため、これがどのような形になるかはわかりません。

ここに画像の説明を入力してください

于 2012-12-08T11:52:37.063 に答える
2

関数ポインタの定義は、UML仕様の範囲外です。さらに、多くのUMLモデリングソフトウェアでサポートされていないのは言語固有の機能です。したがって、最初の質問に対する一般的な回答は、この機能を回避することを示唆していると思います。提供したトリックはEnterpriseArchitectにのみ関連しており、他のUMLモデリングツールとは互換性がありません。他のUMLソフトウェアで関数ポインタがどのようにサポートされているかを次に示します。

MagicDraw UMLはC++FunctionPtr、FPクラスメンバーに<< >>ステレオタイプを使用しC++FunctionSignature、関数プロトタイプに<<>>を使用します。

コードのサンプル(公式サイトから取得-「C ++コード生成のためのtypedefと関数ポインターのモデリング」ビューレットを参照):

class Pointer
{
    void (f*) ( int i );
}

対応するUMLモデル:

MagicDrawUMLの関数ポインタ

Objecteeringは、対応するC++TypeExprノートを使用してFP属性を定義します。

IBMのRationalSoftwareArchitectは、関数ポインターをサポートしていません。ユーザーは、コード->UMLおよびUML->コード変換中に変更されないままになっているユーザー定義セクションの生成されたコードにそれらを追加する場合があります。

于 2012-12-05T17:31:36.843 に答える
1

私の考えでは、UMLインターフェースをstruct-with-function-pointersCイディオムにマップしたいと思っています。

Interface1は、モデルの重要な要素です。あらゆる場所で関数ポインタオブジェクトタイプを宣言すると、ダイアグラムが判読できなくなります。

Enterprise Architectを使用すると、独自のコードジェネレーターを指定できます。コードテンプレートフレームワークを探します。新しいステレオタイプを使用して、Cの既存のコードジェネレーターを変更できるはずです。

于 2012-12-11T12:51:05.000 に答える
1

私には正しいようです。単一の関数ポインターの型と関係を記述するための低レベルの詳細に飛び込む必要があるかどうかはわかりません。私は通常、インターフェースの記述は、その内部要素を分解する必要なしに十分な詳細化であることに気付きます。

于 2012-12-01T21:00:47.000 に答える
1

関数ポインタをクラスで仮想的にラップできると思います。UMLはコードの青写真レベルである必要はないと思います。概念を文書化することがより重要です。

于 2012-12-08T11:57:43.553 に答える
1

私はエンタープライズアーキテクトと何らかの形で連携することができました。それは少しハッキーな解決策ですが、それは私のニーズを満たしています。私がしたこと:

  1. FuncPtrという名前の新しいクラスステレオタイプを作成します。ここのガイドに従いました: http ://www.sparxsystems.com/enterprise_architect_user_guide/10/extending_uml_models/addingelementsandmetaclass.html これを行ったとき、プロファイルの新しいビューを作成しました。だから私はそれを私のメインプロジェクトの外に封じ込めておくことができます。

  2. クラスコードテンプレートを変更しました。基本的にC言語を選択し、クラステンプレートから始めて、[新しいステレオタイプオーバーライドの追加]をクリックし、FuncPtrを新しいオーバーライドとして追加します。

  3. その新しいテンプレートに次のコードを追加します。

%PI="\n"%
%ClassNotes%
typedef %classTag:"returnType"% (*%className%)(
%list="Attribute" @separator=",\n" @indent="    "%
);
  1. 属性宣言コードテンプレートを変更しました。以前と同じように、新しいステレオタイプを追加します

  2. 次のコードを新しいテンプレートに追加します。

%PI = ""%%attConst == "T"?"const": ""%

%attType%

%attContainment == "参照による"?"*": ""%

%attName%

EnterpriseArchitectで関数ポインタを配置するために私がしなければならなかったのはこれだけです。関数ポインタを定義したいときは、次のようにします。

  1. 通常のクラスを作成する
  2. タグ「returnType」に、必要なリターンのタイプを追加します
  3. パラメータの属性を追加します。

このようにして、他のクラス(構造)および演算子の属性またはパラメーターとして含めることができる新しい型を作成します。選択可能なタイプとしてツール内で参照されなかったため、演算子自体にはしませんでした。

したがって、関数ポインタへのtypedefとして特別なステレオタイプ化されたクラスを使用するのは少しハッキーです。

于 2014-11-04T20:06:42.573 に答える
0

最初の例のように、分類子を使用しますが、プロファイルに隠します。概念の説明を明確にするために、それらが含まれていると思います。しかし実際には、ステレオタイプの全体的な考え方は、「ノイズ」の問題を回避するために詳細をプロファイルに抽象化することです。EAはプロファイルの処理に非常に適しています。

最初の例と異なるのは、データ型ステレオタイプではなく、プリミティブ型ステレオタイプを分類することです。データ型はドメインスコープオブジェクトですが、プリミティブ型はUMLのスコープ外で定義されたセマンティクスを持つアトミック要素です。これは、特にプロファイルにメモを追加したり、functionPointerのような非常に明確なステレオタイプ名を付けたりできないということではありません。

于 2012-12-06T17:40:01.170 に答える