-2

Is there software/tool to see the order in which header files are being included after compilation of a C++ application? I find myself often running into circular dependency issues and seeing the "undefined reference" error message :(

UPDATE #1

I am familiar with header include guards and I am using them, but for some reason I'm still having an issue with circular dependency.

In my case, I have many situations where a class A uses class B, and vice versa. In those cases, I use forward declaration for example "class B;" at the top of A.h and vice versa.

Should it ever be the case where I'll need to do "#include "B.h"" at the top of A.h? Or is "class B;" sufficient on its' own at the top of A.h?

UPDATE #2

Hello, below is a snippet of the code that I am having trouble compiling/linking. There are 3 classes below:

A.cpp

#include "A.h"

namespace sef
{
    A::A() {
        // TODO Auto-generated constructor stub
        b = 0;
    }

    A::~A() {
        // TODO Auto-generated destructor stub
    }

    bool A::execute()
    {
        C::connectAndSaveFile();
        b->start();
        return true;
    }
}

A.h

#ifndef A_H_
#define A_H_

//#include "B.h"
class B;
#include "C.h"

namespace sef {

    class A {
    public:
        B* b;
        bool execute();

        A();
        virtual ~A();
    };

}

#endif /* A_H_ */

B.cpp

#include "B.h"

B::B() {
    // TODO Auto-generated constructor stub
    engine = 0;
    bool result = engine->execute();
    cout << result << endl;
}

B::~B() {
    // TODO Auto-generated destructor stub
}

void B::start()
{

    cout << "B::start()" << endl;
}

B.h

#ifndef B_H_
#define B_H_

#include <iostream>
#include <string>
using namespace std;

//#include "A.h"

namespace sef {
    class A;
}

class B
{
public:
    sef::A* engine;

    B();
    virtual ~B();
    void start();
};

#endif /* B_H_ */

C.cpp

#include "C.h"

C::C() {
    // TODO Auto-generated constructor stub

}

C::~C() {
    // TODO Auto-generated destructor stub
}

void C::connectAndSaveFile()
{
    cout << "C::connectAndSaveFile()" << endl;
}

C.h

#ifndef C_H_
#define C_H_

#include <iostream>
#include <string>
using namespace std;

class C {
public:
    C();
    virtual ~C();

    static void connectAndSaveFile();
};

#endif /* C_H_ */

I seem to be getting the error:

***g++ -O0 -g3 -Wall -c -fmessage-length=0 -o "src\\A.o" "..\\src\\A.cpp" 
..\src\A.cpp: In member function 'bool sef::A::execute()':
..\src\A.cpp:23:4: error: invalid use of incomplete type 'class B'
In file included from ..\src\A.cpp:7:0:
..\src\A.h:12:7: error: forward declaration of 'class B'***
Sam
  • 7,252
  • 16
  • 46
  • 65
code
  • 5,294
  • 16
  • 62
  • 113
  • Are you familiar with header include guards (http://stackoverflow.com/questions/14290026/linking-h-files-with-c-with-ifdef-header-guards)? – Nerf Herder Jun 03 '14 at 18:13
  • 2
    @NerfHerder that wouldn't fix a circular dependency problem. – juanchopanza Jun 03 '14 at 18:13
  • 3
    If you need software to figure out what headers are being included in what order you're doing something wrong. – Syntactic Fructose Jun 03 '14 at 18:15
  • 4
    Use [header include guards](http://stackoverflow.com/questions/8020113/c-include-guards) and [forward declarations](http://stackoverflow.com/questions/7757519/forward-declarations) properly, instead of asking for a tool to solve these problems (which is OT anyway)! – πάντα ῥεῖ Jun 03 '14 at 18:17
  • Thank you. I see. I have updated my original post. I am familiar with header include guards and forward declaration but I can't seem to figure out why I am still getting undefined reference issues. – code Jun 03 '14 at 18:24
  • 1
    In answer to "should it ever be the case where..."; the answer is yes. A forward declaration of `B` only lets you use pointers and references to `B` (as a first approximation); you will need the full B.h if you want to use a `B` by value or use any of its members. – dlf Jun 03 '14 at 18:33
  • 2
    A snippet of code that produces one of your errors would go a long way toward helping us recommend a way to solve the circular dependency. – dlf Jun 03 '14 at 18:36
  • Thank dlf, I am going to add a snippet of code right now – code Jun 03 '14 at 19:05
  • Hi all. I have updated the original post with sample code. I stripped it down to the bare minimum as much as I could. I seem to have a trouble getting this to compile together. I am not sure when to use forward declare and when to include – code Jun 03 '14 at 19:08
  • ou should be able to compile the header files on their own. – Ed Heal Jun 03 '14 at 19:11
  • 1
    I seem to be getting the message: g++ -O0 -g3 -Wall -c -fmessage-length=0 -o "src\\A.o" "..\\src\\A.cpp" ..\src\A.cpp: In member function 'bool sef::A::execute()': ..\src\A.cpp:23:4: error: invalid use of incomplete type 'class B' In file included from ..\src\A.cpp:7:0: ..\src\A.h:12:7: error: forward declaration of 'class B' – code Jun 03 '14 at 19:15

1 Answers1

2

Your forward declarations are a good start, but in addition, A.cpp will need to include B.h and C.h since it dereferences a B* and calls a static function in C. Similarly, B.cpp needs A.h since it dereferences an A*. There may be other issues too, but that should get you on the right track.

Long story short, a forward declaration of class A only tells the compiler that A is the name of a class. This is enough for it to know what you mean when you say A* or A& (or a couple of other things), but if you want to actually call a function on an A, or access a member variable, or return/take an A by value, or have a variable of type A1, you need the complete definition of A from its header.

1 Basically, any operation that requires the compiler to know either sizeof(A) or information about its members/ancestors.


Also, this wasn't your question, but this code will give you undefined behavior:

B::B() {
    // TODO Auto-generated constructor stub
    engine = 0;
    bool result = engine->execute();
    cout << result << endl;
}

You're effectively setting engine to null and then calling a function on it.

And even further off the original topic, it's generally considered bad practice to using namespace std in a header file because everyone who includes it will be forced to use that namespace too, whether they want to or not.

dlf
  • 9,045
  • 4
  • 32
  • 58
  • Thanks for your answer dlf. I guess my question is... how come forward declaration is not needed here? They both depend on each other. I am trying to figure out when i should forward declare versus use include – code Jun 03 '14 at 20:18
  • I made the modifications: A.cpp includes B.h and C.h ... and B.cpp includes A.h ... but now I am seeing the error message: "B" does not name a type – code Jun 03 '14 at 20:20
  • A.h does need to forward declare `class B` so the compiler can make sense of `B* b`. That's all the information that's needed there. But A.cpp actually decomposes a `B`, so it needs the full B.h. You should leave the forward declarations you already had in the different headers, but also add the includes I mentioned to the cpps. – dlf Jun 03 '14 at 20:21
  • Omg. I see what you mean now! – code Jun 03 '14 at 20:26
  • Thank you for your help dlf. My next question is... so this entire time I've had the impression that for A.cpp, the only thing it would ever need is A.h at the top. And I had the impression that every include/forward decl should be inside A.h. But now it seems that sometimes the A.cpp file will need to include other header files. Is this the standard approach of including headers? – code Jun 03 '14 at 20:28
  • Is it correct to say... I should only include necessary class/header information in A.h and include other header files in A.cpp if other class member functions/variables are used? – code Jun 03 '14 at 20:29
  • In general, you should minimize the practice of including headers in headers because this can blow up your build times by making everything depend on everything else. Sometimes you've got to do it, but I, at least, will always opt to put a forward declaration in the header and the include in the cpp when it's possible. – dlf Jun 03 '14 at 20:29
  • Your second comment came in while I was typing my last one. Yes, that is exactly right. – dlf Jun 03 '14 at 20:32
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/55020/discussion-between-user1456962-and-dlf). – code Jun 03 '14 at 20:33
  • Hi dlf, I have a question. What if I just combined two lines each time, wouldn't something like this solve any scenario : "class B; #include "B.h" " – code Jun 03 '14 at 23:51
  • In a sense yes; but a) the include would make the forward declaration redundant, and b) routinely using includes where a f.d. would suffice can get you to a place where changing one "hot" header means you need to recompile most of your project. – dlf Jun 04 '14 at 12:07