开发者

C++ class, its base class and circular include includes [duplicate]

开发者 https://www.devze.com 2022-12-09 18:56 出处:网络
This question already has answers here: Resolve build errors due to circular dependency amongst classes
This question already has answers here: Resolve build errors due to circular dependency amongst classes (12 answers) Closed 3 years ago.

FILE #开发者_Go百科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.


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 ;-)


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.


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.


#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.


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.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号