1

次のように C++ で Visitor パターンを実装したいと思います。

class Visitor{
public:
  virtual ~Visitor();
  virtual void visit(C & t)=0;
};

class V : public Visitor{
public:
  void visit(C &c);
};

class C{ 
public:
  void accept(Visitor &v){ v.visit(*this); }
};

しかし、コンパイラは 2 つの構文エラーについて不平を言います: 不明な識別子 C とビジターです。問題はどこだ?

4

4 に答える 4

5

コンパイラが見た瞬間

virtual void visit(C & t)=0;

名前Cは不明です。

class C前に前方宣言する必要がありますVisitor

class C;

class Visitor{
...
}
于 2012-10-26T12:10:58.937 に答える
4

C++ 言語では、コンパイラはまだ定義されていない名前を先読みしません。つまり、より適切に言えば、先読みする場合とそうでない場合があります。

たとえば、次のように言うことができます

struct Foo
{
    Foo(int x) : m_x(x) { }
    int m_x;
};

m_x何を定義する前に使用してもコンパイラは文句を言いませんm_xが、モジュールレベルではこの先読みは存在しません:

struct Foo
{
    Bar *p;  // Error, Compiler doesn't know what Bar is
};

// Too late, the compiler is not going to read down here while
// analyzing Foo.
struct Bar
{
    int x;
};

何かを定義する前に使用する必要がある場合、どのように解決しますか? 特別な「前方宣言」を使用することにより、その名前の何かがあることのみを述べ、後でそれが具体的に何であるかを定義します...たとえば

struct Foo; // There will be a struct Foo defined somewhere

struct Bar
{
    Foo *p; // Fine, even if the compiler doesn't really know Foo
};

struct Foo
{
    Bar *q; // Fine and no forward needed... Bar is known at this point
};

多かれ少なかれルールは次のとおりです。単一のクラスでは、すべてのメソッドは他のすべてのメソッドとすべてのメンバーをクラスで後で定義されている場合でも見ることができますが、代わりにモジュールレベルでは、すべての名前を使用する前に知っておく必要があります。

より複雑なパターンが必要な場合もあります。

struct Foo;

struct Bar
{
    void doit(Bar x);
};

struct Foo
{
    void doit_too(Foo x);
};

void Foo::doit(Bar x) { ... }
void Bar::doit_too(Foo x) { ... }

最後のケースでは、両方のクラスの宣言の後に両方のメソッドの実装を配置する必要があります。これは、それFooがクラスであることを知っているだけでは、コピー操作をコンパイルするのに十分ではないためです (メソッドのパラメーターは値によって渡されていることに注意してください)。 、ポインターまたは参照によるものではありません)。

于 2012-10-26T12:23:34.107 に答える
3

4 行目では、何が何だかわかりませんC。不明な識別子です。

これにより、定義がVisitor無効になるため、後で使用しようとするとVisitor別のエラーが発生します。

于 2012-10-26T12:11:30.057 に答える
3

問題は、ビジターが使用する時点でクラス C が定義されていないことです。それを一番上に移動するか(クラスC)、または:

class C;

上記の前方宣言をファイルの先頭に追加します。参照パラメータとしてのみ使用するため、これで十分です。

于 2012-10-26T12:11:37.503 に答える