1

我想在 C++ 中实现访问者模式,如下所示:

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

在第四行,没有人知道是什么C。这是一个未知的标识符。

这使得定义Visitor无效,因此当您稍后尝试使用Visitor时会发生另一个错误。

于 2012-10-26T12:11:30.057 回答
3

问题是 C 类在访问者使用它时没有定义。将其移至顶部(即 C 类)或:

class C;

在文件顶部添加上述前向声明。由于您仅将其用作参考参数,因此这就足够了。

于 2012-10-26T12:11:37.503 回答