views:

244

answers:

5

FILE #1 (foo.h):

#ifndef FOO_H_
#define FOO_H_
#include "baseclass.h"
#include "bar.h"
class Bar;
class Foo : public baseclass {
public:
bar *varBar;
};
#endif

FILE #2 (bar.h):

#ifndef BAR_H_
#define BAR_H_
#include "foo.h"
class Foo;
class Bar {
public:
Foo *varFoo;
};
#endif

FILE #3 (baseclass.h):

#ifndef BASECLASS_H_
#define BASECLASS_H_
#include "foo.h"
class Foo;
class baseclass {
public:
list<Foo*> L;
};
#endif

But I get an compile error in file #1 in line class Foo : public baseclass:

Error: expected class-name before »{« token

If I add class baseclass; bevor class declaration, I get this error:

Error: invalid use of incomplete type »struct baseclass«

So my question is, how can I resolve circular dependencies with baseclasses?

Ask if you don't get somepoint. I allready tried to change the order of includeing the headers, but no luck so far. Thanks for any hint.

EDIT: Note: I am using include guards EDIT2: It is not limited to pointers, so I remove them, just in case. EDIT3: Added baseclass (forgot O.o) EDIT4: Now it should be clear and without anymore flaws, the problem persisits with this code.

+2  A: 

Do you have include guards on your headers? The code above includes a.h and b.h recursively, thus defining a whole bunch of headers.

The forward declaration class b; removes the need for the #include "b.h" in FILE1. Similarly, #include "a.h" should be removed from FILE2.

Billy ONeal
Better yet, just use '#pragma once' directive
Sergey
#pragma once is MSVCC only. Other C++ compilers do not support it.
Billy ONeal
I have guards, no pragma
penguinpower
//#include "Foo.h"class Foo;throws this error against my head:Error: invalid use of incomplete type »struct Foo«
penguinpower
#pragma once is not the standard and may not work on some compilers.
the_drow
@BillyONeal: It works on gcc as well iirc
the_drow
+3  A: 

The usual way is to add the following around your header files:

#ifndef FOO_H_
#define FOO_H_
#include "baseclass.h"
#include "bar.h"
class Bar;
class Foo : public baseclass {
public:
bar *varBar;
};
#endif

and

#ifndef BAR_H_
#define BAR_H_
#include "foo.h"
class Foo;
class Bar {
public:
Foo *varFoo;
};
#endif

Most compilers (gcc, VC) also accept #pragma once at the beginning of the file, but I'm pretty sure it is not part of the current C++ standard.


EDIT:

Sure enough, as the ISO/IEC 14882 states, a #pragma "causes the implementation to behave in an implementation-defined manner. Any pragma that is not recognized by the implementation is ignored."

It is currently still the same with C++0x.

So I would stick with the first old-fashioned way of doing that ;-)

RedGlyph
You need to define the definition after the #ifndef.
Billy ONeal
You're absolutely right, thanks! So silly of me... it's fixed now.
RedGlyph
I am allrady using this, but it does not fix the problem anyways
penguinpower
Okay, you should have put that in the first place because it is very misleading...
RedGlyph
I am sorry, just forgot it..
penguinpower
+2  A: 
#ifndef _BAR_H_
#define _BAR_H_    
#include "baseclass.h"

class Bar;
class Foo : public baseclass {
public:
    Bar *varBar;
};

#endif

If a class is forward declared and you are using only a pointer or a reference to a member of that class, then you do not need to include the header for it. The same goes for the class in the other file. But yes, make sure that you use include guards in all of your header files (#ifndef...#endif) to prevent multiple inclusions of headers during compilation.

zdawg
+1 That's sort of the whole point of forward declaring classes and breaking circular dependencies. - However, avoid identifiers that begin with an underscore (followed by an upper-case letter)
UncleBens
+3  A: 

What you seem to have posted is to have a Bar member in the Foo, and a Foo member in the Bar. That is a circular dependency you need to break - if every Foo contains a Bar which contains a Foo then constructing either never terminates.

class Foo : public baseclass {
    public:
        Bar varBar;
};

class Bar {
    public:
        Foo varFoo;
};

Instead you need to use a pointer or reference to the Foo or Bar in at least one of them:

class Bar;
class Foo : public baseclass {
    public:
        Bar& varBar;
};

class Bar {
    public:
        Foo varFoo;
};

As the circularity is broken and you're only using a reference to the object, you don't need to have the full definition of the referred-to type, and can use a forward declaration.

Include guards are good for users, but try and not rely on them when developing. If the compiler has to check whether or not something has been included, it's still doing work even if it has optimisations for guards/pragmas. You do need to have some understanding of what depends on what to break the initial cycle, and putting guards on the files won't help you with that.

Pete Kirkham
even if they are all pointers, it still breaks. Thanks for noting that.
penguinpower
I think I got a cluttered makefile -.- thanks for pointing these things out, I will have a cleanlook after cleaning my makefiele.
penguinpower
@Pete: well done, +1 for seeing further than the header dependencies.
RedGlyph
+1 - But I'm not sure I understand the point about include guards. They need to be in pretty much every header file - there are only a few odd-ball exceptions.
Michael Burr
If you understand what depends on what, they you don't need any include guards. They are only have an effect if you include something twice without thinking, which can happen in third party code, but shouldn't happen within your own code.
Pete Kirkham
A: 

baseclass.h doesn't need anything from foo.h, so remove #include "foo.h" from baseclass.h.

You have a Foo variable in your Bar, and a Bar in your Foo. That isn't going to work: you can't have an egg in a box and a box in an egg. One or both of them should be a pointer.

Dave Hinton
Baseclass includes a list of Foo Pointers. So I think it's required to include Foo.
penguinpower