I see this question has been discussed in various places, e.g. here,here,here and here .But, i have still not been able to relate to the questions aforementioned.
My situation: I am trying to implement a simple generic visitor pattern in C . The hosts in this pattern are different pets, these are in a file called Pet.h. The visitors are in a separate header called Visitors.h.
The concrete Pet classes accept
, generic visitor classes(See Comment 0 in Pet.h), and the generic visitor classes visits
the generic Pet classes. So, there is a natural cyclic dependency.
Earlier, when all the code was in a single header, there were no problems. Now there is. To illustrate, here is the Pet.h class. P.S: I am using Visual Studio 2017.
#pragma once
#include <string>
#include "Visitors.h"
namespace pet
{
class Pet {
public:
virtual ~Pet() {}
virtual void accept(temp_visitor::PetVisitor& v) = 0; //Comment 0 Pet accepts a gneric PetVisitor
virtual std::string getAnimal() = 0;
private:
std::string color_;
};
template <typename Derived>
class Visitable : public Pet {
public:
using Pet::Pet;
Visitable() = default;
Visitable(const std::string& animal) : animal_(animal) {}
void accept(temp_visitor::PetVisitor& v) override {
v.visit(static_cast<Derived*>(this));
}
std::string getAnimal() override
{
return animal_;
}
std::string animal_;
};
class Cat : public Visitable<Cat> {
using Visitable<Cat>::Visitable;
};
class Dog : public Visitable<Dog> {
using Visitable<Dog>::Visitable;
};
}
And here is the Visitors.h file. The void visit(pet::Pet* p) gives the following error "use of undefined type pet::Pet on using p->getAnimal()
#include<iostream>
#pragma once
namespace pet
{
class Pet; //Comment 1. Attempted forward declaration.
}
namespace temp_visitor
{
template <typename ... Types>
class Visitor;
template <typename T>
class Visitor<T> {
public:
virtual void visit(T* t) = 0;
};
using PetVisitor = Visitor<pet::Pet>;
class FeedingVisitor : public PetVisitor {
public:
void visit(pet::Pet* p) override { std::cout << "Feed veggies to the " p->getAnimal() << std::endl; } //Comment 2: Gives the following error "use of undefined type pet::Pet"
};
}
So how do i fix this problem ?
CodePudding user response:
You need to move the FeedingVisitor
to a new header and cpp as well. In header you will have #include "Visitors.h"
, forward declration for Pet
and in cpp #include "Pet.h"
Something like Visitors.hpp
namespace pet {
class Pet; //Comment 1. Attempted forward declaration.
}
namespace temp_visitor
{
template <typename ... Types> class Visitor;
template <typename T> class Visitor<T>
{
public:
virtual void visit(T* t) = 0;
};
}
FeedingVisitor.hpp
#include "Visitors.h"
namespace temp_visitor
{
using PetVisitor = Visitor<pet::Pet>;
class FeedingVisitor : public PetVisitor {
public:
void visit(pet::Pet* p) override; // only declaration
};
}
FeedingVisitor.cpp
// move the definition to cpp
void temp_visitor::FeedingVisitor::visit(pet::Pet* p) {
std::cout << "Feed veggies to the " p->getAnimal() << std::endl;
}