Hello,
I'm new here, so I hope I'll ask my question correctly. I have an assignment to create a "text-based cosmic adventure" and all went well until now. My project is separated into several header and implementation files. Problem arises only when I include certain file in another header file. Compiler writes the famous "myClass was not declared in this scope" error. And I really don't know what I'm doing wrong (or better said what to do).
I have a tip, but better first some code:

// Location.h
#include "MainMenu.h"
class Location 
{...}

// MainMenu.h
#include "Planet.h"
class MainMenu
{...}

// Planet.h
#include <vector>
#include "Location.h"
class Planet 
{
...
vector<Location> location; // error: 'Location' was not declared in this scope 
...
}

I think there could be some sort of cycle between Location.h and Planet.h. First Location.h includes MainMenu.h, which then includes Planet.h, that includes again Location.h. But I really don't know how to prevent this, because I need all headers to be included.

Do you think this is the reason or is it something else? Could you please show me a solution to this problem?
Thank you very much

Note: When I do not include MainMenu.h in Location.h, the error in Planet.h doesn't occur. but I'd really like to be able to use MainManu functionality (well, better said, I need to, because it controls the whole game).


P.S.: At the beginning of every file I of course have that thing against cycles:

#ifndef LOCATION_H
#define LOCATION_H
...
#endif

so there shouldn't be any "inclusion cycle problem".

None of your sample classes have semi-colons after their definitions. Is this an error in your example or does it appear in your code as well? Without those closing semi-colons, the compiler will get VERY confused.

class SampleClass {
  // member declarations
};  //<---required semi-colon

Yes, I have semi-colons in the real program.

Yeah, it's a cyclical definition. This is one reason why header guards exist. Instead of, for example, only including "Location.h" in "Planet.h" you should also include "MainMenu.h". Then, you would make similar changes in the other headers as well. Also, check your file paths. Make sure that Planet.h is actually finding the Location.h file so that it can include it.

I suspect though that you'll have to go to forward declarations:

class ClassA;    //forward declaration of ClassA

class ClassB {   //formal definition of ClassB
 private:
   vector<ClassA> vMyAObjects;
};

class ClassA {   //formal definition of ClassA
  ...
};

However, a lingering question remains. Why is MainMenu dependent on Planet, and by extension, Location? How are they related, if at all? I think you need to take another look at your program's structure in general. I can see how Location and Planet could be related, but I can't see how either one would relate to MainMenu.

I tried to add the MainMenu to Planet and the location error didn't occur, but another error was written - in MainMenu it didn't know the Planet type.
After few minutes of panic I found a solution - dirty, but did the job. I included MainMenu.h in Location.cpp and it to my surprise it worked.

To explain my usage of this class - I only needed to call a specific method of MainMenu in the Location class, that ends the game. I really didn't need the whole class, but I couldn't do this without it, could I?

But whole this problem makes me worried about programming of larger applications. How to prevent this including issues? Are there any "best practices"? I can imagine how absolutely terrible this could get when one has to deal with tens (hundreds?) of files.

And when should I use forward declarations? I read that they should be used only in classes where they'll be just pointers. When you need to approach objects of this class, you have to include its header. This makes fwd dec, imho, not very useful.

I almost forgot to thank you, so I do so now. And when you'll answer some of my questions, I'll arrange a feast in your honor :).

>>To explain my usage of this class - I only needed to call a specific method of MainMenu in the Location class, that ends the game. I really didn't need the whole class, but I couldn't do this without it, could I?
I'm sure there is a way, but I don't know anything about your classes or code except that their names are Location, MainMenu, and Planet so I really can't offer any insight.

>>But whole this problem makes me worried about programming of larger applications. How to prevent this including issues? Are there any "best practices"? I can imagine how absolutely terrible this could get when one has to deal with tens (hundreds?) of files.
Unfortunately, you can never completely avoid it. It's a situation that you have to think about and work through while you're designing your system(s). Inheritance hierarchies will probably help a little, but they won't solve all issues. For example, Location could potentially be a "base" class and Planet could potentially "derive" from it.

>>And when should I use forward declarations? I read that they should be used only in classes where they'll be just pointers. When you need to approach objects of this class, you have to include its header. This makes fwd dec, imho, not very useful.
Generally, you use a forward declaration when you have 2 classes whose definitions rely on each other. If you define 2 classes, let's call them "ClassA" and "ClassB", that have Objects of each other as members (ClassA contains a ClassB object, and ClassB contains a ClassA object) you need one. What happens is if you define ClassA first, and it has a member that is a ClassB object? The compiler doesn't know anything about ClassB yet so it throws an "Undefined Identifier" error.

Given that, you decide to switch it up and define ClassB first. Problem is, you now have the same issue, but in reverse. The compiler doesn't know anything about ClassA yet so it throws another error.

To correct this circle of errors (can you say "Catch 22"?) you add a Forward Declaration. A Forward Declaration works like a function prototype and tells the compiler that the class exists, but is defined later or elsewhere. Additionally, in order for this to work, they can't both have an actual object of the other otherwise you get a circular definition and an infinitely large object. To correct this, at least one of the classes must have a pointer to an object of the other class. For example, a ClassB object might have a pointer to the ClassA object that contains it.

That was a truly comprehensive answer. I start to really like this forum :).

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.