Circular Dependencies / Incomplete Types
Asked Answered
E

3

6

In C++, I have a problem with circular dependencies / incomplete types. The situation is as follows:

Stuffcollection.h

#include "Spritesheet.h";
class Stuffcollection {
    public:
    void myfunc (Spritesheet *spritesheet);
    void myfuncTwo ();
};

Stuffcollection.cpp

void Stuffcollection::myfunc(Spritesheet *spritesheet) {
    unsigned int myvar = 5 * spritesheet->spritevar;
}
void myfunc2() {
    //
}

Spritesheet.h

#include "Stuffcollection.h"
class Spritesheet {
    public:
    void init();
};

Spritesheet.cpp

void Spritesheet::init() {
    Stuffcollection stuffme;
    myvar = stuffme.myfuncTwo();
}
  • If I keep the includes as shown above, I get the compiler error spritesheet has not been declared in Stuffcollection.h (line 4 in the above). I understand this to be due to a circular dependency.
  • Now if I change #include "Spritesheet.h" to the Forward Declaration class Spritesheet; in Stuffcollection.h, I get the compiler error invalid use of incomplete type 'struct Spritesheet' in Stuffcollection.cpp (line 2 in the above).
  • Similarly, if I change #include "Stuffcollection.h" to class Stuffcollection; in Spritesheet.h, I get the compiler error aggregate 'Stuffcollection stuffme' has incomplete type and cannot be defined in Spritesheet.cpp (line 2 in the above).

What can I do to solve this problem?

Enroll answered 5/10, 2011 at 19:31 Comment(5)
Repeat of https://mcmap.net/q/1774497/-double-include-solution/… (that was posed by the same author not long ago!)Mabuse
@EdHeal: I have the highest voted answer on that Q and it is not a duplicate. There is a subtle difference, You would know if you read carefully.Deliberate
This isn't the actual code from your program. This code could not generate the error message you indicate. Please reduce your program to a minimal, complete sample program and copy-paste (not retype) that code here. See sscce.org.Husbandman
@Als - I thourgh that the previous question it was obvious to #include in the .cpp files.Mabuse
@EdHeal: Yes, but the OP didn't understand it & S/He won't if we just close this saying duplicate.Deliberate
D
4

You should include Spritesheet.h in Stuffcollection.cpp
Just use forward declaration in the header file not the cpp file, that solves the circular dependency of the header file. The source file has no circular dependency actually.

Stuffcollection.cpp needs to know the complete layout of class Spritesheet(because you dereference it), So you need to include the header which defines the class Spritesheet in that file.

From your previous Q here, I believe that class Stuffcollection is used in the class declaration of Spritesheet header file and hence the above proposed solution.

Deliberate answered 5/10, 2011 at 19:34 Comment(3)
Thank you! Getting this to work really makes my whole code a lot simpler, since I can now finally remove all my workarounds (mainly copied functions...). About paragraph 3: I noticed that I don't need to include Stuffcollection.h into Spritesheet.h, it is sufficient to include it into Spritesheet.cpp.Enroll
Just noticed: Actually that is exactly what sth said :)Enroll
@Ben: Glad you could get it to work, Always post all relevant information with a Q that helps us answer your Q better, like in this case Your first Q indicated(Since You didn't show the code in that file but included it) probably you needed the include.Deliberate
S
3

Use this form for your nested includes:

Stuffcollection.h

#ifndef STUFFCOLLECTION_H_GUARD
#define STUFFCOLLECTION_H_GUARD
class Spritesheet;
class Stuffcollection {
  public:
  void myfunc (Spritesheet *spritesheet);
  void myfuncTwo ();
};
#endif

Stuffcollection.cpp

#include "Stuffcollection.h"
#include "Spritesheet.h"

void Stuffcollection::myfunc(Spritesheet *spritesheet) {
  unsigned int myvar = 5 * spritesheet->spritevar;
}

void Stuffcollection::myfuncTwo() {
  //
}

Spritesheet.h

#ifndef SPRITESHEET_H_GUARD
#define SPRITESHEET_H_GUARD
class Spritesheet {
  public:
  void init();
};
#endif

Spritesheet.cpp

#include "Stuffcollection.h"
#include "Spritesheet.h"

void Spritesheet::init() {
  Stuffcollection stuffme;
  myvar = stuffme.myfuncTwo();
}

General rules I follow:

  • Don't include an include from an include, dude. Prefer forward declarations if possible.
    • Exception: include system includes anywhere you want
  • Have CPP include everything it needs, not relying upon H recursively including it files.
  • Always use include guards.
  • Never use pragma
Spears answered 5/10, 2011 at 19:45 Comment(3)
Another good rule: every .cpp should include its own .h first (so I'd switch the order of the includes in your Spritesheet.cpp). That way there is at least one .cpp that includes any .h without anything before it, thus ensuring that the .h is not missing any includes.Dempsey
This way works for me, where I have included Alan's tip about including the h corresponding to the cpp first. Many thanks.Enroll
@Enroll -- please upvote the answer(s) that helped you, and accept (by clicking on the check mark) the answer that helped the most.Husbandman
F
2

Spritesheet.h doesn't need to include Stuffcollection.h, since no Stuffcollection is used in the class declaration of Spritesheet. Move that include line to Spritesheet.cpp instead and you should be fine.

Film answered 5/10, 2011 at 19:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.