Sign in to follow this  
GameCreator

Base Class Undefined

Recommended Posts

I made a few changes to my project and it now has two "bass class undefined" errors (for the same class, in the attached picture).  I believe, from researching this online, that the problem is that I have circular references.  However, I don't know how to remove it.  To start, I would need to know what order my project is compiled in.  Is there a file list that Visual Studio provides?  I'm pretty sure it all starts at App.cpp, then App.h but then what's the next file?  How does VS choose which CPP file comes next?  Is it alphabetical?  If there are 3 header files in a file, will it immediately do all of those headers next?  I only have one header in each CPP file (the H file by the same name) but the headers may have 2 or 3.

 

Here's a screenshot of my project with the problematic class showing.

 

[attachment=23507:screen.gif]

 

Thank you for any help!

 

(By the way, I read that in other situations forward declaration is the way to go but that it doesn't work with base classes.)

 

Share this post


Link to post
Share on other sites

How does VS choose which CPP file comes next?  Is it alphabetical?

When you build your project there will usually be a window with the compiler output in the bottom. If you want to, you can read the sequence things happen out of there. However, that is not going to be relevant for your problem.
 
It would really help to post the relevant code (for example where is characterclass actually defined) instead of screenshots as well as complete error messages.
 

If there are 3 header files in a file, will it immediately do all of those headers next?  I only have one header in each CPP file (the H file by the same name) but the headers may have 2 or 3.

Headers are irrelevant. The compiler only deals with .cpp files and an #include directive is just a convenient automatic way to paste the complete content of whatever file is referenced there. That happens during preprocessing before the compiler even sees it.

The most likely issues are that you did not include the header which declares characterclass or your inclusion guard did not use a unique enough define. Note that using '#pragma once' instead of manual inclusion guards would solve this problem immediately and is available on all three compilers an average person is likely to encounter (MSVC, gcc and clang).

On a more serious note, avoid 'using namespace' directives in headers. If you really need to, do that in implementation files or at function scope.

Share this post


Link to post
Share on other sites


To start, I would need to know what order my project is compiled in.  

Nope, the order of compilation is irrelevant.

 

Remember, C++ source files are compiled in isolation. For each source file, any header files that are #included are copied into one big "translation unit" by the preprocessor, and then the compiler compiles this. So what is happening is that the result of your #including either does not include the base class or it appears after the derived class.

 

If you actually have a circular reference, the technical solution is to use forward declarations in the header files and only to #include the relevant headers in the source file. This is good practise in general for reducing compilation time and needless recompilation.

 

The design solution is to remove one of the dependencies, or de-couple it by introducing an intermediary. A non-circular example of this is a class that handles input. In a simple game, this class might directly invoke functions on a Player object, for instance. To break this direct dependency, the Input class could instead bind std::function<>s to different controls, and then some higher level glue code creates the functions that call the Player functions.

 

Like BitMaster, I'd recommend you show us the header files that are affected.

Share this post


Link to post
Share on other sites

Changing all the headers to #pragma once did not change the result.

 

And as I mentioned in my original post, from what I'm reading online, forward declarations don't work for base classes.

"Derived classes definitely need to know the structure of their parent, not just that the parent exists, so a forward declaration would be insufficient."  from here.

 

But here's my entire set of code files, should you want to take a look: [attachment=23508:Source.rar]

 

Oh, and excuse all the globals.  ;)

Edited by GameCreator

Share this post


Link to post
Share on other sites

If there are 3 header files in a file, will it immediately do all of those headers next? I only have one header in each CPP file (the H file by the same name) but the headers may have 2 or 3.


Headers aren't compiled. They're effectively just text that gets copied into the file that includes them. e.g., this code:

// base.h
class base {};
// derived.h
#include "#base.h"
class derived : base {};
is expanded into this equivalent code:
// derived.h
// base.h
class base {};
class derived : base {};
That's all that headers do and are for. They let you write up common bits of code and paste them automatically into other bits of code.

So far as your problem, it's usually caused by a circular dependency in includes. As you can imagine from the above example, you cannot have base.h include derived.h and derived.h include base.h, as then you'd have an infinite recursion of includes. Trying to do this will cause includes to not work properly as the compiler has rules for how to avoid an infinite include chain like that. That appears to be what you're running into.

I'm not going to download a random .rar file from the Internet to pour through your code. Upload it to a code hosting site like Github or at least use something like pastebin, or better yet just include the relevant snippets here.

Share this post


Link to post
Share on other sites

The solution is very simple in this case. What is the purpose of including character.h and player.h in world.h? There's nothing in world.h that depends on the contents of neither of the two files, and those unnecessary and seemingly harmless includes cause circular includes and symbols to not be defined in the correct places within a translation unit.

 

Thank you.  world.cpp uses the player class.  And I was under the impression from somewhere that you should only put one header include in cpp files whenever possible.  So I put player.h in world.h instead.  But when issues started happening, I added character.h as well to make sure it's included first as I thought: what's the harm?  Better to make sure it's included as it can't be included twice anyway, right?  And yet there are these circular references which, in my less-than-knowledgable mind, shouldn't even be possible (but I'm starting to understand a bit that the system doesn't work the way I thought it did, thanks to people's help here).  I'll see what happens if I put player.h into world.cpp instead but it seems like that would do the same thing...

Edited by GameCreator

Share this post


Link to post
Share on other sites

Thank you.  world.cpp uses the player class.  And I was under the impression from somewhere that you should only put one header include in cpp files whenever possible.

That is completely untrue. The aim in general is to limit the number of includes in headers files (don't include what you do not need, use forward declarations where possible). Implementation files will often need the complete definition of things they use and then you need to include all relevant headers there.

And yet there are these circular references which, in my less-than-knowledgable mind, shouldn't even be possible (but I'm starting to understand a bit that the system doesn't work the way I thought it did, thanks to people's help here).

Both the manual #ifdef/#define inclusion guards and #pragma once are not magic. They avoid repeated declaration errors but you still cannot have two headers depending on declarations in the other.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this