Home > Blockchain >  Visitor Pattern Error(use undefined type)
Visitor Pattern Error(use undefined type)

Time:02-01

I am studying visiting patterns. However, the following error occurs. not defined. The cat class only has its own name and age. agevisitor and namevisitor, which inherit Visitor interface, output age and name.

I tried forward declaration, but the error of C2027 appears as it is. help me :(

that's my code

#include <iostream>
using namespace std;

class Visitor;

class Cat
{
public:
    Cat(string name, int age) : name_(name), age_(age) {}

    void Speak() {
        cout << "meow" << endl;
    }

    void Accept(Visitor* visitor) {
        cout << "use implementation of visitor" << endl;
        visitor->visit(this); // #undefined type error
    }

public:
    string name_;
    int age_;

public:
    friend class AgeVisitor;
    friend class NameVisitor;
};

class Visitor
{
public:
    virtual void visit(Cat* cat) {}
};

class AgeVisitor : public Visitor
{
public:
    virtual void visit(Cat* cat) {
        cout << "cat is " << cat->age_ << "years old" << endl;
    }
};

class NameVisitor : public Visitor
{
public:
    virtual void visit(Cat* cat) {
        cout << "cat's name is " << cat->name_ << endl;
    }
};

int main()
{
    Cat* first_cat = new Cat{ "kitty", 5 };
    
    Visitor* age_visitor = new AgeVisitor();
    first_cat->Accept(age_visitor);
}

Severity Code Description Project File Line Suppression State Error C2027 use of undefined type 'Visitor' DesignPattern C:\Users\sueng\source\repos\DesignPattern\DesignPattern\DesignPattern.cpp 18

CodePudding user response:

In case of circular dependency like in the Visitor pattern, ideally you should first decompose your code into headers and sources. This is because forward declared classes have incomplete type, so you can use pointers and references to them, you can also use them as return types, but you can't use any of their methods or create an actual instance either on the stack or dynamically, because the class layout is not known at the time.

Example Cat.hpp:

class Visitor;
class AgeVisitor;  // needed just for the friend declaration
class NamedVisitor;
class Cat
{
public:
    Cat(string name, int age);
    void Accept(Visitor* visitor);  // note that we only declare the class Cat, no methods definitions

public:
    string name_;
    int age_;

public:
    friend class AgeVisitor;
    friend class NameVisitor;
};

Then Visitor.h and similar in case of NamedVisitor.h etc ... :

class Cat;
class Visitor
{
public:
    virtual void visit(Cat* cat);
};

And then in Cat.cpp you can include the headers with the visitors definitions which allows you to use their methods:

#include "Cat.hpp"
#include "Visitor.hpp"

Cat::Cat(string name, int age): name_(name), age_(age) {}

void Cat::Accept(Visitor* visitor) {
    cout << "use implementation of visitor" << endl;
    visitor->visit(this);  // now you can use it, because Visitor class declaration is available
}

Alternatively you can copy-paste all the code in the presented order to your main.cpp but it's a bad habit. Live demo with everything copy-pasted in 1 source.

CodePudding user response:

Forward declaration of a class without declaring its methods allows only to use the class name in the places which don't need information about the methods of the class. If you use methods (even implicitly, such as calling constructor for the local variable) you need to declare them forward also. E.g. the following code will not compile:

class A;

class B
{
public:
    B();
};

class C
{
public:
    void Run()
    {
        A* pa; // ok, forward class declaration is enough to declare pointers
        A a;   // compile error, since here we call ctor, but we haven't declared it
        B b;   // ok, we declared ctor
    }
};

// can be in a different file
B::B()
{}
  • Related