C ++中的访问者模式

时间:2012-10-26 12:08:46

标签: c++ visitor-pattern

我想在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 个答案:

答案 0 :(得分:4)

目前编译器看到了

virtual void visit(C & t)=0;

名称C未知。

您需要在class C

之前转发声明Visitor
class C;

class Visitor{
...
}

答案 1 :(得分:3)

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

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

答案 2 :(得分:3)

问题是访客使用它时未定义C类。将其移至顶部(C类)或:

class C;

在文件顶部添加上述前向声明。由于您只将它用作参考参数,这应该足够了。

答案 3 :(得分:3)

在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是一个类是不够的,无法编译复制操作(请注意参数在方法中已经通过值传递,而不是通过指针或引用传递。