Home > Back-end >  A class pointer does not name a type
A class pointer does not name a type

Time:10-25

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.

  • Related