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?

Ben
  • 15,938
  • 19
  • 92
  • 138
  • Repeat of http://stackoverflow.com/questions/7665912/double-include-solution/7665937#7665937 (that was posed by the same author not long ago!) – Ed Heal Oct 05 '11 at 19:36
  • 1
    @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. – Alok Save Oct 05 '11 at 19:38
  • 1
    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 http://sscce.org/. – Robᵩ Oct 05 '11 at 19:38
  • @Als - I thourgh that the previous question it was obvious to `#include` in the .cpp files. – Ed Heal Oct 05 '11 at 19:43
  • @EdHeal: Yes, but the OP didn't understand it & S/He won't if we just close this saying duplicate. – Alok Save Oct 05 '11 at 19:44

3 Answers3

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.

Community
  • 1
  • 1
Alok Save
  • 202,538
  • 53
  • 430
  • 533
  • 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. – Ben Oct 05 '11 at 22:04
  • Just noticed: Actually that is exactly what sth said :) – Ben Oct 05 '11 at 22:08
  • @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. – Alok Save Oct 06 '11 at 05:17
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
Robᵩ
  • 163,533
  • 20
  • 239
  • 308
  • 2
    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. – Alan Stokes Oct 05 '11 at 20:17
  • This way works for me, where I have included Alan's tip about including the h corresponding to the cpp first. Many thanks. – Ben Oct 05 '11 at 22:17
  • @Ben -- please upvote the answer(s) that helped you, and accept (by clicking on the check mark) the answer that helped the most. – Robᵩ Oct 06 '11 at 02:53
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.

sth
  • 222,467
  • 53
  • 283
  • 367