2

I have a class RenderMachine which includes RenderObject and vice versa. I know there have been tons of questions about this error, but the solution for this doesn't do anything.

They say the error is mostly because a include-loop but I don't have one because in the RenderObject header I only allocate memory for a pointer to RenderMachine and vice versa.

RenderObject.h
#pragma once
#include "RenderMachine.h"

class RenderObject
{

public:
    RenderObject(RenderMachine* rm){}

}; 
RenderMachine.h
#pragma once
#include "RenderObject.h"

class RenderMachine
{

public:
    void add(RenderObject* renderObject);

};

The exact error is

error: expected ‘)’ before ‘*’ token
RenderObject(RenderMachine* rm)
                          ^

Edit:

#include "RenderMachine.h"
class RenderMachine;

class RenderObject : public sf::Drawable
{

private:
    int renderId;

public:
    RenderObject(RenderMachine* rm){ (*rm).add(*this); }
    int getRenderId() const { return renderId; }
#include "RenderObject.h"
class RenderMachine
{

std::vector< std::vector<sf::Drawable*> > renderVector;

public:
    void add(RenderObject* renderObject);

And RenderMachine.cpp

#include "RenderMachine.h"
void RenderMachine::add(RenderObject* renderObject)
{
    renderVector[(*renderObject).getRenderId()].push_back(renderObject);
}
  • 1
    have you tried a forward declaration? – Code-Apprentice Sep 17 '19 at 19:54
  • Yes I already tried that and when the constructor definiton is empty it works just fine but when I call a method of RenderMachine I get this error: `error: invalid use of incomplete type ‘class RenderMachine’` – Earl of Lemongrab Sep 17 '19 at 19:58
  • 2
    @Che You should probably show that code with the particular error instead. Without forward declaration it can clearly not work. But if it doesn't work with forward declaration either, there must be a second, different, issue. – walnut Sep 17 '19 at 19:59
  • 2
    For the question as is, comment aside, I would say possible duplicate of [Resolve build errors due to circular dependency amongst classes](https://stackoverflow.com/questions/625799/resolve-build-errors-due-to-circular-dependency-amongst-classes) Especially second half of the top answer. – walnut Sep 17 '19 at 20:03
  • For the edited question, see [this answer](https://stackoverflow.com/a/625801/11941443) on the same duplicate. – walnut Sep 17 '19 at 20:07

2 Answers2

3

Your call to add in the constructor of RenderObject should be done when RenderMachine is known (when it's a complete type). This goes for all calls to an object of the other type that you now have in your header files. Like this:

// RenderObject.h
class RenderMachine;

class RenderObject {
public:
    RenderObject(RenderMachine* rm);
};
// RenderMachine.h
class RenderObject;

class RenderMachine {
public:
    void add(RenderObject* renderObject);
};
// RenderObject.cpp
RenderObject::RenderObject(RenderMachine* rm) {
    rm->add(this);
}
// RenderMachine.cpp
void RenderMachine::add(RenderObject* ro) {
}
Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108
2

You have a classic chicken-and-egg problem. The compiler cannot parse one header without first parsing the other header, because the classes in the headers refer to each other.

The solution is to use a forward declaration like this:

#include "RenderMachine.h"

class RenderMachine; // forward declaration

class RenderObject
{

public:
    RenderObject(RenderMachine* rm){}

}; 
Lee Jenkins
  • 2,299
  • 3
  • 24
  • 39
  • Yeah I did that but still there is this `error: invalid use of incomplete type ‘class RenderMachine`error – Earl of Lemongrab Sep 17 '19 at 20:08
  • Is that error for RenderObject.h or RenderObject.cpp? – Lee Jenkins Sep 17 '19 at 20:17
  • @LeeJenkins Note that there doesn't seem to be a `RenderObject.cpp` file. The constructor definition is inline in the header file here. – Code-Apprentice Sep 17 '19 at 21:27
  • 1
    @Code-Apprentice Right you are! I lazily scrolled up to Ted Lyngmo's answer -- my mistake. Of course, that is the source of the OP's error: the compiler cannot complete the constructor in one header because the code depends on the other header. Chicken and egg. The solution, along with the forward declaration, is to put the constructor in a cpp file, as Ted Lyngmo has done. – Lee Jenkins Sep 18 '19 at 02:16