ManuelSchneid3r
ManuelSchneid3r

Reputation: 16121

Visitor pattern in C++

I want to implement the Visitor pattern in C++ like this:

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); }
};

But the compiler complains abount 2 syntax errors: Unknown identifier C and Visitor. Where is the problem?

Upvotes: 1

Views: 812

Answers (4)

6502
6502

Reputation: 114599

In the C++ language the compiler will not look ahead for names that are yet to be defined or, to say it better, sometimes it does and sometimes it doesn't.

You can say for example

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

and the compiler will not complain even if you used m_x before defining what m_x is, but however at the module level this look ahead is not present:

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;
};

How do you solve cases in which you need to use something before defining it? By using a special "forward declaration", in which you only state that there will be something with that name and you define later what it is in the specific... for example

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
};

More or less the rule is: in a single class all methods can see all other methods and all members even if they are defined later in the class, at a module level instead every name must be known before it can be used.

Sometimes a more complex pattern is needed, like

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) { ... }

In the last case you are forced to put the implementation of both methods after the declarations of both classes because just knowing that Foo is a class is not enough to be able to compile a copy operation (note the parameter in the methods has been passed by value, not by pointer or reference).

Upvotes: 5

Science_Fiction
Science_Fiction

Reputation: 3443

Problem is Class C is not defined at the point Visitor uses it. Either move it to the top (class C that is) or:

class C;

Add the above forward declaration at top of file. Since you only use it as a reference param, this should suffice.

Upvotes: 3

Daniel Daranas
Daniel Daranas

Reputation: 22644

At the fourth line, nobody knows what C is. It is an unknown identifier.

This makes the definition of Visitor not valid, hence when you try to use your Visitor later another error occurs.

Upvotes: 3

Andriy
Andriy

Reputation: 8604

At the moment the compiler sees

virtual void visit(C & t)=0;

name C is unknown.

You need to forward-declare class C before Visitor

class C;

class Visitor{
...
}

Upvotes: 5

Related Questions