8

次のコードは合法的なC++ですか?

class Foo
{
  class Bar;

  void HaveADrink(Bar &bar);
  void PayForDrinks(Bar &bar);

  public:
  void VisitABar(int drinks);
};

class Foo::Bar
{
  public:
  int countDrinks;
};

void Foo::HaveADrink(Bar &bar)
{
  bar.countDrinks++;
}
void Foo::PayForDrinks(Bar &bar)
{
  bar.countDrinks = 0;
}
void Foo::VisitABar(int drinks)
{
  Bar bar;
  for (int i=0; i<drinks; i++) HaveADrink(bar);
  PayForDrinks(bar);
}

Visual C ++とGCCはどちらもそれを受け入れますが、コードは私には少し奇妙に思えるので、将来のコンパイラーによって拒否されるのは嫌です。

それでも、このパターンはコンパイル時の依存関係を減らすのに役立つようです。同じcppにあるいくつかの関数間で共有される「コンテキスト」(変数の束)を渡すために使用される構造体を宣言するためによく使用します。このようにして、パブリックインターフェイスに「コンテキスト」定義を導入する必要はありません。

4

2 に答える 2

10

合法であり、実装の詳細を外の世界に隠すのに実際に役立ちます。

于 2009-10-14T07:51:04.397 に答える
9

[編集]私はもともとこれが「pimplイディオム」だと言っていました:http ://c2.com/cgi/wiki ?PimplIdiomですが、これはpimplの一部にすぎないことに同意します。この手法は、pimplで使用されます。

あなたはクラスFoo内でクラスバーを「転送」しています。Fooのdefinigino内で、Barのサイズを必要とするようなことを何もしない限り、完全に合法です。ポインタまたは参照(Bar *またはBar&)を使用してBarを参照できますが、次のようにFooでデータメンバーを宣言する場合:

プライベート:Bar _bar;

それはうまくいきません。その理由は、Fooの定義がFooのサイズを決定するのに十分でなければならないためです。Fooの定義内では、Barのサイズが不明であるため、Fooのサイズが不確定になります。ただし、ポインタを使用すると機能します。

プライベート:Bar * _bar;

Barが後でどのように定義されるかに関係なく、ポインタのsizeofは同じであり、したがって既知であるためです。

于 2009-10-14T08:00:02.213 に答える