I have 3 C files:
Main.cpp
#include "FileA.h"
FileA.h
#include "FileB.h"
class FileA{
private:
FileB* b; //It doesn't give error here!
};
FileB.h
class FileB{
private:
FileA* A; //The error is here!
};
When I run the Main.cpp file, the compiler says:
'FileA' does not name a type, did you mean 'FileB'?
This is the first time I use StackOverflow to ask question so it's kinda messy, sorry. Anyone knows how to fix this problem and the cause of it ? Thank you in advance!
CodePudding user response:
#include
preprocessor directive copies the content of the file. So the content of Main.cpp
becomes the content FileA.h
since that #include
is the only expression in the file.
The file FileA.h
starts by including FileB.h
so the content of Main.cpp
becomes:
Main.cpp
preprocessor output:
class FileB{
private:
FileA* A; //The error is here!
};
class FileA{
private:
FileB* b; //It doesn't give error here!
};
As you can see on the line with the eror FileA
is not declared yet. Since both FileA
and FileB
need each other you need to foward delcare the classes before use in each header. And don't forget to guard against recursive includes. I use #pragama once
because is simpler and supported on all major compilers, even if it is not standard:
Main.cpp
#include "FileA.h"
FileA.h
#pragma once
#include "FileB.h"
class FileB;
class FileA{
private:
FileB* b;
};
FileB.h
#pragma once
#include "FileA.h"
class FileA;
class FileB{
private:
FileA* A;
};
CodePudding user response:
Spent too much time commenting and not answering. This is pretty much what Bolov showed, but with more of the gory details.
Let's looks at this the way the compiler does. Whenever the compiler, really the preprocessor, finds an include
directive, it replaces the include
with the content of the included file.
The compiler starts with Main.cpp. It sees the
#include "FileA.h"
and replaces it with FileA.h so now you have
#include "FileB.h"
class FileA{
private:
FileB* b; //It doesn't give error here!
};
The compiler picks up where it left off and finds
#include "FileB.h"
and replaces it with FileB.h. Now you have
class FileB{
private:
FileA* A; //The error is here!
};
class FileA{
private:
FileB* b; //It doesn't give error here!
};
No more preprocessor work is required, so the compiler looks at the combined file. FileB
is the first thing defined, and it needs a declaration of FileA
to satisfy FileA* A;
. The compiler hasn''t seen FileA
yet, so it emits an error and keeps going. It finds FileA
and the FileB* b;
member, but at this point it's seen FileB
, so no error.
When you have a pointer or reference it's enough for the compiler to know that the identifier exists, even if it doesn't know what the named type looks like because it doesn't have to hold an instance of the type. The fix is to forward declare FileA ahead of
FileB`
class FileA; // forward declaration
class FileB{
private:
FileA* A; //The error is here!
};
class FileA{
private:
FileB* b; //It doesn't give error here!
};
Now FileA* A;
is satisfied that there is such a thing as a FileA
It doesn't know enough to construct one or how to access anything inside a FileA
yet, but no one has asked it to.
This resolves to a FileB.h that looks like
class FileA; // forward declaration
class FileB{
private:
FileA* A; //The error is here!
};
Bolov makes a very good point about preventing multiple includes of the same file. Sometimes you can get away with it, but often you wind up with recursive loops and nigh-inscrutable error messages. Best to be avoided with your choice of Include Guard mechanism.