Reputation: 833
Could someone explain why I receive a syntax error: Identifier 'Bar' during building without the inclusion of class Bar;
in the foo.hpp
header file?
I don't receive any errors in Visual Studio 2019 before building, and the build order appears to be bar
, then foo
, then main
, so following the #include
statements it would seem as though the bar
header file is first included inside the foo
header during the build.
I have included code below outlining the basic problem.
//Foo header file
#pragma once
#include "bar.hpp"
#include <iostream>
class Bar; //Commenting this line out results in no longer being able to build the project
class Foo {
public:
Foo();
void pickSomething(Bar& bar);
};
//Foo cpp file
#include "foo.hpp"
Foo::Foo() {
std::cout << "Made Foo" << std::endl;
}
void Foo::pickSomething(Bar& bar) {
bar.getSomething();
std::cout << "Picked something!" << std::endl;
}
//Bar header file
#pragma once
#include "foo.hpp"
#include <iostream>
class Foo;
class Bar {
public:
Bar(Foo& foo);
void getSomething();
};
//Bar cpp file
#include "bar.hpp"
Bar::Bar(Foo& foo) {
std::cout << "Made bar" << std::endl;
}
void Bar::getSomething() {
std::cout << "Gave something!" << std::endl;
}
//main file
#include "foo.hpp"
#include "bar.hpp"
int main() {
Foo foo;
Bar bar(foo);
foo.pickSomething(bar);
return 0;
}
Upvotes: 1
Views: 638
Reputation: 7445
Summary:
foo.hpp
includes bar.hpp
and bar.hpp
includes foo.hpp
. This is a cyclic dependency.#pragma once
makes sure to not to load the same header again, if it is already loaded.
Only the compilation of bar.cpp
fails (foo.cpp
and main.cpp
will be successfully compiled)
Let's follow the pre-processor when compiling bar.cpp
. Things happen in the following order.
bar.cpp
includes bar.hpp
bar.hpp
includes foo.hpp
. (Note the following two points)
bar.hpp
and will avoid entering it again in current cycle.Bar
(declaration of class Bar
) is not still loaded as foo.hpp
is included before thatfoo.hpp
try to include bar.hpp
bar.hpp
, hence this is ignored !Foo
class declaration uses a symbol called Bar
. But this is not declared before !The unknown symbol Bar
could have represented many things (a class, a macro etc..). So the compiler (rightfully) fails as it doesn't know how to treat it.
The solution is forward declaration. There, you are guaranteeing the compiler that the symbol Bar
is representing a class. As long as you are not doing anything where the compiler need to know about the class layout (e.g. define a member function of type Bar
, access members of Bar
etc...) the compilation will succeed.
Upvotes: 1
Reputation: 249462
foo.hpp
and bar.hpp
do not depend on each other, so forward declarations are a good way to avoid a circular dependency between their header files. Only the .cpp
files actually need to include both header files.
Upvotes: 0