简体   繁体   中英

C++ circular header includes - how can I solve this type?

I implemented a visitor design pattern. I want to eliminate the circular header includes. The code below is working, g++ compile it.

I have a file: Classes.h It has base and derived class declaration, also has Classes.cpp with the definitions of methods.

Classes.h:

#include "VisitorDesignPattern/Visitor.h"

class Visitor;
class DerivedVisitorA;
class DerivedVisitorB;

class Base
{
    public:
       ...
       virtual void accept(Visitor& v) = 0;
};

class DerivedA : public Base
{
    public:
        void accept(Visitor &v);
};

class DerivedB : public Base
{
    public:
        void accept(Visitor &v);
};

Classes.cpp contains the definitions, definitons of accept method, as well, as I mentioned.

Visitor.h:

#include "../Classes.h"

class Base;
class DerivedA;
class DerivedB;

class Visitor
{
    public:
        virtual void Visit(DerivedA &derivedA) = 0;
        virtual void Visit(DerivedB &derivedB) = 0;
};

class DerivedVisitorA : public Visitor
{
    public:
        void Visit(DerivedA &derivedA);
        void Visit(DerivedB &derivedB);
};

class DerivedVisitorB : public Visitor
{
    public:
        void Visit(DerivedA &derivedA);
        void Visit(DerivedB &derivedB);
};

Visitor.cpp contains the definition of methods.

I am using this in every.h file:

#ifndef VISITOR_H
#define VISITOR_H
...
#endif

#ifndef CLASSES_H
#define CLASSES_H
...
#endif

So in this case how can I eliminate the circular header includes?

In your example, you don't need to include the other header in either of them.

You only need to declare types that you mention and define the ones that you use. Having a type pointer/reference in a function signature is not using it. Accessing said type's fields (explicitly or implicitly) or metadata (size, alignment, etc.), as I assume you would do inside Visitor::Visit() , is.

// Only a declaration. At this point the compiler doesn't know anythng about this type.
struct A;

// Doesn't compile, because B has an implicit default constructor, which the compiler can't generate, because it doesn't know about A's constructor.
// struct B { A member; };

// Compiles, because because the size of a pointer (a reference) is the same for all types.
struct C { A& member; };

// Compiles, since it's only a definition - no code is generated.
void f1(A);

// Doesn't compile, because the compiler needs to know the size of a function's arguments to generate code.
// void f2(A) {}

// Compiles, because the size of a pointer (a reference) is the same for all types.
void f3(A&) {}

// Doesn't compile, because A::foo() hasn't been declared
// void f4(A& a) { a.foo(); }

// A declaration. Now the compiler knows the size of this class and its members.
struct A {
    void foo();
    void bar() {};
};

// A definition for the previously declared f1(), compiles becase A is complete type
void f1(A a) { a.bar(); }

// Compiles, but produces a linker error because it can't find the definition for A::foo()
// void f4(A& a) { a.foo(); }

void A::foo() {}

// Compiles and links
void f4(A& a) { a.foo(); }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM