I'm trying to separate the following two classes so each class can be defined in its own Header:
#include <iostream>
class Boo;
class Foo
{
public:
Foo(Boo *booPtr)
:booPtr(booPtr){};
virtual ~Foo(){};
Boo *booPtr;
};
class Boo
{
public:
Boo()
:foo(this){};
virtual ~Boo(){};
Foo foo;
int num = 32;
};
int main()
{
Boo *boo = new Boo;
std::cout << "booPtr : " << boo->foo.booPtr->num << '\n';
delete boo;
}
The Result:
booPtr : 32
Program ended with exit code: 0
And here is my failed attempt at separation:
"Foo.hpp"
#ifndef Foo_hpp
#define Foo_hpp
#include <stdio.h>
#include "Boo.hpp"
class Foo
{
public:
Foo(Boo *booPtr)
:booPtr(booPtr){};
virtual ~Foo(){};
Boo *booPtr;
};
#endif /* Foo_hpp */
"Boo.hpp"
#ifndef Boo_hpp
#define Boo_hpp
#include <stdio.h>
#include "Foo.hpp"
class Boo
{
public:
Boo()
:foo(this){};
virtual ~Boo(){};
Foo foo; // Error : Field has incomplete type 'Boo'
int num = 32;
};
#endif /* Boo_hpp */
"main.cpp"
#include <iostream>
#include "Foo.hpp"
#include "Boo.hpp"
int main()
{
Boo *boo = new Boo;
std::cout << "booPtr : " << boo->foo.booPtr->num << '\n';
delete boo;
}
But I can't build the code since it generate's the following error:
Boo.hpp -> Foo foo; -> "Field has incomplete type 'Boo'"
How can I fix my code?
You have one file that includes the other and vice versa. This creates a cycle of inclusion.
Realize that the #include macro does nothing but to replace itself (that is, it's line) with the other file. This makes it obvious why you can't have file A include file B.
The obvious solution is to put a forward declaration of Boo in Foo:
#ifndef Foo_hpp
#define Foo_hpp
#include <stdio.h>
class Boo;
class Foo
{
public:
...
Strangely, you already did this before you separated them.
Now a little bit more theory for you: A class is technically a data storage. It needs to know it's size in order to reserve memory. Therefore, it needs to know all the sizes of it's members, which it can only know when they are declared. Therefore, a class needs to include the declaring headers of each class it has as a member. However, a pointer to an object is different (same goes for references). A pointer always takes the same size, that is 32 or 64 bit, depending on your platform (probably 64 bit since we have 64 bit platforms nowadays). Therefore, the class does not need to know the class it points at, the memory it reserves for it's pointer member is always of the same size. That's why a forward declaration, that says nothing about a classes size, is fine here.
While circular inclusion by itself, proper include-guards assumed, is not an error, remember it's just textual replacement:
Make sure all the permutations are viable and have the same meaning!
In your case, replace the inclusion of "Boo.hpp" with the forward-declaration, which you used for a reason in the merged source.
Or, you know, simply abandon splitting the header:
Remember that classes are not necessarily the proper unit of organization.
Addendum on circular includes, starting with Foo.hpp:
#ifndef FOO
#define FOO // (!)
// now including BOO!
#ifndef BOO
#define BOO
// now including FOO a g a i n
// as FOO i s already defined, all that remains is:
#ifndef FOO
#endif
class Boo { }; // now lacking definition of Foo...
#endif // BOO
class Foo { };
#endif // FOO (first one)
Analogously for Boo.hpp (you'd only need a pre-declaration of Foo, but there is none as the definition again follows afterwards...).
As you see, circular includes, appropriate include guards provided, won't result in endless self inclusion. However, the outcome is not the one you intended.
Related
I'm looking to create two classes, each of which contains an object of the other class type. How can I do this? If I can't do this, is there a work-around, like having each class contain a pointer to the other class type? Thanks!
Here's what I have:
File: bar.h
#ifndef BAR_H
#define BAR_H
#include "foo.h"
class bar {
public:
foo getFoo();
protected:
foo f;
};
#endif
File: foo.h
#ifndef FOO_H
#define FOO_H
#include "bar.h"
class foo {
public:
bar getBar();
protected:
bar b;
};
#endif
File: main.cpp
#include "foo.h"
#include "bar.h"
int
main (int argc, char **argv)
{
foo myFoo;
bar myBar;
}
$ g++ main.cpp
In file included from foo.h:3,
from main.cpp:1:
bar.h:6: error: ‘foo’ does not name a type
bar.h:8: error: ‘foo’ does not name a type
You cannot have two classes directly contain objects of the other type, since otherwise you'd need infinite space for the object (since foo has a bar that has a foo that has a bar that etc.)
You can indeed do this by having the two classes store pointers to one another, though. To do this, you'll need to use forward declarations so that the two classes know of each other's existence:
#ifndef BAR_H
#define BAR_H
class foo; // Say foo exists without defining it.
class bar {
public:
foo* getFoo();
protected:
foo* f;
};
#endif
and
#ifndef FOO_H
#define FOO_H
class bar; // Say bar exists without defining it.
class foo {
public:
bar* getBar();
protected:
bar* f;
};
#endif
Notice that the two headers don't include each other. Instead, they just know of the existence of the other class via the forward declarations. Then, in the .cpp files for these two classes, you can #include the other header to get the full information about the class. These forward declarations allow you to break the reference cycle of "foo needs bar needs foo needs bar."
That doesn't make sense. If A contains B, and B contains A, it would be infinite size. Imagine putting having two boxes and trying to put both into each other. Doesn't work, right?
Pointers work though:
#ifndef FOO_H
#define FOO_H
// Forward declaration so the compiler knows what bar is
class bar;
class foo {
public:
bar *getBar();
protected:
bar *b;
};
#endif
Why if I have
in foo.h:
class Foo
{
}
void Bar(const Foo& foo);
it works but:
in foo.h:
class Foo
{
}
in bar.cpp
#include "foo.h"
void Bar(const Foo& foo);
doesn't work (unknown type name 'Foo' is its exact words)?
I don't know what about my question isn't specific and forward declarations don't work they just create a error 'duplicate symbol' so im just going to post the code im working with
in creatures.h
#ifndef CREATURES_H_
#define CREATURES_H_
#include <string>
#include "textio.hpp"
class Creature {
private:
protected:
int statBlock[10];
public:
std::string name = "foo";
Creature ();
void ai(int);
};
class Dwarf : public Creature {
private:
public:
std::string name = "Dwarf";
Dwarf (int);
void defaultDwarfGen();
};
main.cpp
#endif
#include "creatures.hpp"
#include "textio.hpp"
#include <iostream>
int main(int argc, char const *argv[]) {
Dwarf creature_1(0);
return 0;
}
textio.hpp:
#ifndef TEXTIO_H
#define TEXTIO_H
#include <iostream>
#include "creatures.hpp"
void challenge(const Creature& param);
#endif
Your problem is that you are including textio.hpp in creatures.hpp so first time that compiler see function void challenge(const Creature& param)Creature class isn't defined.
When you include createures.hppin textio.hpp CREATURES_H_ is already defined and bypass inclusion)
You can fix it deleting this include or declaring a forward definition for Creature class
In order to answer this question properly, you must provide foo.h, foo.cpp, bar.h, and bar.cpp
In short:
To make use of Bar in foo.h, foo.h must have the declaration for Bar.
To make use of Foo in bar.h, bar.h must have the declaration for Foo.
To make use of Bar in foo.cpp, foo.h or foo.cpp must have the declaration for Bar.
To make use of Foo in bar.cpp, bar.h or bar.cpp must have the declaration for Foo.
When I say, "must have declaration for", you can #include the appropriate header.
If you are trying to use Foo in Bar and Bar in Foo, then you've got a circular reference. The way we overcome this is with a forward declaration.
You can read about forward declarations here: https://isocpp.org/wiki/faq/misc-technical-issues#forward-decl
Note: I have found the issue with how my Xcode was compiling the below and it appears unrelated to the topic discussed herein. When I have more details I will provide them here.
I recommend voting to close my question as "too localized" since it was an Xcode problem, unrelated to the c++ code itself. Many thanks for the help all the same as I did learn from the answers.
The below question (now answered and resolved) was caused by a confusing exclusion of a file from the Xcode target, thus there were no compiler errors even though the file had problems.
I have a pure virtual interface and want to define its factory method, which returns a subclass of this interface. This works fine:
struct MyVirt{
...all virtual stuff
};
class SubVirt; //forward declaration allows factory:
MyVirt*CreateClass(){
return new SubVirt;
}
Update: Some of the comments say that forward declare is not enough to achieve the above, but that's not correct. You can accomplish the above fine without the full definition of the SubVirt class.
Now, what I want to do is have a custom constructor that takes arguments. As such:
MyVirt*CreateClass(){
return new SubVirt(arg 1, etc);
}
The problem is that a class forward declaration is no longer sufficient. It needs to see the class definition or its header. This means I can either move the factory method to the file where SubVirt is defined, or I have to include that file in the above file, which creates a circular dependency.
Is there a way to forward declare the custom constructor instead? That would make it all much simpler.
Your CreateClass function looks odd, you miss () in function definition. Should be like this:
MyVirt* CreateClass()
{
return new SubVirt(arg 1, etc);
}
When return a pointer, compiler needs to know the concrete type and constructor, so forward declare is not enough.
What you could do is:
in header file: forward declare SubVirt and CreateClass function
cpp file: include MyVirt.h and define CreateClass function
Separate declaration from implementation, like everyone does.
MyVirt.h:
struct MyVirt{
...all virtual stuff
};
MyVirt.cpp:
#include "MyVirt.h"
Implementation of MyVirt
SubVirt.h:
#include "MyVirt.h"
struct SubVirt : MyVirt {
...all SubVirt stuff
};
SubVirt.cpp:
#include "SubVirt.h"
Implementation of SubVirt
Factory.h:
struct MyVirt;
MyVirt *CreateClass();
Factory.cpp:
#include "SubVirt.h"
MyVirt *CreateClass() { return new SubVirt() }
This can be accomplished by separating the declaration and implementation.
The key here is to put the definition/implementation above the includes. Suppose you want to separate the classes A and B create two files like the following:
A.hpp
#ifndef A_HPP
#define A_HPP
struct B; // fwd. decl.
struct A {
int v;
A(int v) {
this->v = v;
}
B* createB();
};
#include "B.hpp"
A* B::createA() {
return new A(v);
}
#endif A_HPP
B.hpp
#ifndef B_HPP
#define B_HPP
struct A; // fwd. decl.
struct B {
int v;
B(int v) {
this->v = v;
}
A* createA();
};
#include "A.hpp"
B* A::createB() {
return new B(v);
}
#endif // B_HPP
main.hpp
#include <A.hpp>
#include <B.hpp>
#include <iostream>
int main(int argc, char *argv[]) {
A a(42);
std::cout << a.createB()->createA()->v << std::endl;
return 0;
}
You are of course free to move the implementation into a cpp file instead. This is only the basic recipe which shows how circular dependencies can be solved even for templated classes and functions.
http://codepad.org/IsBzQANX
I'm looking to create two classes, each of which contains an object of the other class type. How can I do this? If I can't do this, is there a work-around, like having each class contain a pointer to the other class type? Thanks!
Here's what I have:
File: bar.h
#ifndef BAR_H
#define BAR_H
#include "foo.h"
class bar {
public:
foo getFoo();
protected:
foo f;
};
#endif
File: foo.h
#ifndef FOO_H
#define FOO_H
#include "bar.h"
class foo {
public:
bar getBar();
protected:
bar b;
};
#endif
File: main.cpp
#include "foo.h"
#include "bar.h"
int
main (int argc, char **argv)
{
foo myFoo;
bar myBar;
}
$ g++ main.cpp
In file included from foo.h:3,
from main.cpp:1:
bar.h:6: error: ‘foo’ does not name a type
bar.h:8: error: ‘foo’ does not name a type
You cannot have two classes directly contain objects of the other type, since otherwise you'd need infinite space for the object (since foo has a bar that has a foo that has a bar that etc.)
You can indeed do this by having the two classes store pointers to one another, though. To do this, you'll need to use forward declarations so that the two classes know of each other's existence:
#ifndef BAR_H
#define BAR_H
class foo; // Say foo exists without defining it.
class bar {
public:
foo* getFoo();
protected:
foo* f;
};
#endif
and
#ifndef FOO_H
#define FOO_H
class bar; // Say bar exists without defining it.
class foo {
public:
bar* getBar();
protected:
bar* f;
};
#endif
Notice that the two headers don't include each other. Instead, they just know of the existence of the other class via the forward declarations. Then, in the .cpp files for these two classes, you can #include the other header to get the full information about the class. These forward declarations allow you to break the reference cycle of "foo needs bar needs foo needs bar."
That doesn't make sense. If A contains B, and B contains A, it would be infinite size. Imagine putting having two boxes and trying to put both into each other. Doesn't work, right?
Pointers work though:
#ifndef FOO_H
#define FOO_H
// Forward declaration so the compiler knows what bar is
class bar;
class foo {
public:
bar *getBar();
protected:
bar *b;
};
#endif
This question already has answers here:
Resolve build errors due to circular dependency amongst classes
(12 answers)
Closed 4 years ago.
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.
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.