web-dev-qa-db-ja.com

C ++のネストされたクラス/転送宣言の問題

ネストされたクラスを前方宣言してから、それを外部クラスの具象(ポインター/参照ではない)データメンバーの型として使用することはできますか?

I.E.

class Outer;

class Outer::MaybeThisWay   // Error: Outer is undefined
{
};

class Outer
{
 MaybeThisWay x;

 class MaybeThatOtherWay;

 MaybeThatOtherWay y;   // Error: MaybeThatOtherWay is undefined
};
32
uj2

このようなネストされたクラスを前方宣言することはできません。

何をしようとしているかに応じて、外側のレイヤーでクラスではなく名前空間を使用できる場合があります。このようなクラスは問題なく転送宣言できます。

namespace Outer {
   struct Inner; 
};

Outer::Inner* sweets;  // Outer::Inner is incomplete so 
                       // I can only make a pointer to it

Outerが絶対にクラスである必要があり、名前空間に分類できない場合は、OuterがInnerを前方宣言するコンテキストで完全な型である必要があります。

class Outer
{
   class Inner;  // Inner forward-declared
};  // Outer is fully-defined now

Outer yes;  // Outer is complete, you can make instances of it
Outer::Inner* fun;  // Inner is incomplete, you can only make 
                    // pointers/references to it

class Outer::Inner 
{
};  // now Inner is fully-defined too

Outer::Inner win;  // Now I can make instances of Inner too
37
janks

含まれているクラスを完全に指定せずにネストされたクラスを前方宣言する方法はありません。この小さなトリックはちょっと問題を修正します

class Outer_Inner
{
};

class Outer
{
public:
   typedef Outer_Inner Inner;
};

これは私の命名規則と同じように機能しますOuter_Innerは有効なクラス名ではないため、ネストされたクラスを参照していることは明らかです。

次のように、ネストされたクラスをまだ転送宣言することはできません。

class Outer::Inner;

ただし、少なくとも次のようにして前方宣言できます。

class Outer_Inner;

Outer_Innerの外観が気に入らない場合は、入れ子になったクラスの命名規則を好みに合わせて採用できます。 Outer__InnerOuter_nested_Innerなど.

15
deft_code

いいえ、でも何が悪いのですか

class Outer {
public:  //or protected or private
    class Inner {
    };

private:
    Inner foo;
};

私が何かを欠落していない限り、ここでは前方宣言は意味がありません(質問に多くの詳細が欠けているため、これは可能です)

クラスが前方宣言されている場合は、前方宣言された型のオブジェクトへの参照またはポインタのみを宣言できます。メンバーや関数へのアクセスなど、他のことはできません。

1
Glen

クラスが前方宣言されている場合(ただし、完全な定義はまだありません)、クラスへのポインターを宣言できるのは、コンパイラーがクラスのサイズ(およびそのフィールドの名前も)をまだ認識していないためです。またはメソッド)。

1
Ken Bloom

参照やポインタではなく、タイプMaybeThatOtherWayの属性を宣言する場合、コンパイラは外部クラスのサイズを決定するためにクラスの完全な定義を知っている必要があります。したがって、ネストされたクラスであるかどうかにかかわらず、フォワード宣言とその種のフィールド宣言は使用できません。

0
Seb

関数のパラメーターまたは静的変数として型が必要な場合は、クライアント側で行うことができます。たとえば、外部からイベント通知を受信するには:

インターフェース:

class Client {
public:
private:
    static void gotIt(int event);
    class Helper;
};

実装:

#include <outer.hpp>

class Client::Helper {
public:
    static void fromOuter(Outer::Inner const& inner) 
    { 
        gotIt(inner.event());
    }
};
0
zzz777