2

Say that we have two classes:

// Object.hpp
class Object
{
    Handler* h;

    Object();
    void method();
};

// Object.cpp
Object::Object()
{
    h = new Handler();
}
// Handler.hpp
class Handler
{
    void update(Object*);
};

// Handler.cpp
void Handler::update(Object* o)
{
    o->method();
}

How to link the four files without there being an inclusion error? I've tried all of the ways that I could think of and that I could find online.

Adding #include in both files will result in this error:

Handler.hpp: error: ‘Object’ has not been declared
         update(Object*);
                ^

If I add a forward declaration of Object in Handler i get this:

Object.hpp: error: ‘Handler’ does not name a type
         Handler handler

Including Object in Handler.hpp and forward declaring Handler in Object.hpp gives this:

Object.hpp: error: field ‘h’ has incomplete type ‘Handler’
         Handler handler;
                 ^

Meanwhile including Handler in Object.hpp an forward declaring Object in Handler.hpp gives this:

Handler.cpp: error: invalid use of incomplete type ‘class Object’
     o->method();
      ^

I can't seem to figure out the way to include the files in each other. This structure is based on the decoupling component pattern from Robert Nystrom's Game Programming Patterns. Any help is appreciated. Thanks

Yksisarvinen
  • 18,008
  • 2
  • 24
  • 52
koraljko
  • 79
  • 8
  • You do know that you can declare a class without defining it? class object; – Surt Apr 01 '20 at 14:38
  • Does this answer your question? [What are forward declarations in C++?](https://stackoverflow.com/questions/4757565/what-are-forward-declarations-in-c) – Yksisarvinen Apr 01 '20 at 14:40
  • both ways of using a forward declaration should be fine. Please provide a [mcve] – 463035818_is_not_an_ai Apr 01 '20 at 14:40
  • Yes, I have tried that, as mentioned in my question - I've tried forward declaring them, and got the errors that I've posted. – koraljko Apr 01 '20 at 14:40
  • 2
    the errors refer to code that is not present in your example. Forward declaratiosn allow you to have pointers and reference, but eg not an object as member – 463035818_is_not_an_ai Apr 01 '20 at 14:41
  • Does this answer your question? [When can I use a forward declaration?](https://stackoverflow.com/questions/553682/when-can-i-use-a-forward-declaration) – Mikel Rychliski Apr 10 '20 at 01:59

2 Answers2

3

The errors you posted do not seem to come from the code you gave.

The problem with

Object.hpp: error: ‘Handler’ does not name a type
         Handler handler  //<-- Declaration of object of type Handler, not pointer

is that handler was declared as an object, not a pointer. Thus, the compiler needs to know the defnition. That is why a forward-declaration is not enough. If you add a forward-declaration of Handler in the Object.hpp you gave, it should work:

// Object.hpp
//forward-declaration of Handler
class Handler;

class Object
{
    Handler* h;

    Object();
    void method();
};
// Object.cpp
//include Handler.hpp

#include "Handler.hpp"
Object::Object()
{
    h = new Handler();
}
// Handler.hpp
//include Object.hpp

#include "Object.hpp"

class Handler
{
    void update(Object*);
};
// Handler.cpp
void Handler::update(Object* o)
{
    o->method();
}

Edited to add include in Object.cpp and remove first paragraph as per @TonyK's comment

melk
  • 530
  • 3
  • 9
  • And, for completeness, in this simple case the problem could also be solved with `class Handler* h;` inside the definition of `Object`. +1. – Pete Becker Apr 01 '20 at 14:52
  • 1
    Your first paragraph is wrong: you don't have to name your parameters in a function declaration. – TonyK Apr 01 '20 at 15:04
  • Yes I don't need to name parameters in the .hpp. Your second paragraph is on the right track but adding an #include the the .hpp also gives an error. The code is correct, the problem is that one of the includes has to go in the *.cpp* file. Check my answer – koraljko Apr 01 '20 at 15:08
  • @korajko True, edited to include the Handler.hpp in Object.cpp – melk Apr 01 '20 at 16:27
  • Looking back at this problem, I think the dependency inversion principle would have helped a lot. Depending on common interfaces could help break the loops that are created when concrete classes depend on each other. (Can't be applied in all situations) – koraljko Apr 28 '22 at 21:59
1

Found the problem. Thank you all for taking the time to try and help me out and especially thanks to @Yksisarvinen for the helpful link.

The problem is that I have placed the #includes in the .hpp file, and this creates a problem for the compiler, even though I have include guards.

I solved this by using only forward declarations in the .hpp files that don't need any code from the included classes, and then added the #include into the .cpp files (where I use methods from the included class).

Basically I did the following:

  • I added a #include "Handler.hpp" in Object.hpp (the Object class contains a Handler object, which calls the constructor which needs an #include)
  • I added only a forward declaration of Object in Handler.hpp (Handler.hpp doesn't need any code from the Object files, it just needs to know that an Object class exists)
  • And then finally I added the #include "Object.hpp" in Handler.cpp (Necessary because I use a method from Object)
koraljko
  • 79
  • 8