12

I have encountered this error many times before and eventually found solutions, but this one has me stumped. I have a class 'Mob' that is inherited by class 'Player'. This is Mob.h:

#pragma once
#include "PlayState.h"
#include "OmiGame/OmiGame.h"
#include "resources.h"

class PlayState;

class Mob
{
private:
    int frames;
    int width;
    int height;
    int time;

    sf::Texture textureL;
    sf::Texture textureR;
    Animation animationL;
    Animation animationR;
    AnimatedSprite sprite;
    bool moveLeft;
    bool moveRight;
    bool facingRight;

public:
    void createMob(std::string l, std::string r, int frames, int width, int height, int time, int x, int y);

    void updateMob(omi::Game *game, PlayState *state);
    void drawMob(sf::RenderTarget &target);

    void setLeft(bool b) { moveLeft = b; }
    void setRight(bool b) { moveRight = b; }
    bool isLeft() { return moveLeft; }
    bool isRight() { return moveRight; }

    sf::Vector2f getPosition() { return sprite.getPosition(); }
};

This is Player.h, as of now it is extremely simple:

#pragma once
#include "OmiGame/OmiGame.h"
#include "PlayState.h"
#include "Mob.h"
#include "resources.h"

class PlayState;
class Mob;

const int playerFrames = 8;
const int playerWidth = 16;
const int playerHeight = 48;
const int playerTime = 50;
const int playerX = 200;
const int playerY = 200;

class Player : public Mob
{ //the error occurs at this line//
public:
    Player();
    void update(omi::Game *game, PlayState *state);
    void draw(sf::RenderTarget &target);
};

And, as you can probably guess, this is the error:

error C2504: 'Mob' : base class undefined   player.h

I have forward declared mob, I have hopefully fixed any circular dependencies. Please can someone help me?

Greg Treleaven
  • 8,124
  • 7
  • 30
  • 30
  • Are the files in the same directory? – ChiefTwoPencils Jul 13 '14 at 17:36
  • You know, it somehow defeats encapsulation if you provide accessors for all your private members... – Deduplicator Jul 13 '14 at 18:11
  • 3
    @Deduplicator It doesn't. Only four private members have accessors because mobs need to react differently based on them, yet they need to share these members so the reused code can also access them. – Greg Treleaven Jul 13 '14 at 20:56
  • @Greg: So they are public members, even though the code tries to deceive you into believing otherwise. – Deduplicator Jul 13 '14 at 21:14
  • 3
    @Deduplicator True, the getter/setter coding style is controversial, but I learned OO programming that way so it's become a habit. It's all down to personal preference and convention. – Greg Treleaven Jul 13 '14 at 21:29

4 Answers4

35

Forward declaring doesn't help for class Player : public Mob because the compiler needs the full definition for inheritance.

So most likely one of your includes in Mob.h is bringing in Player.h which then puts Player ahead of Mob and thus triggers the error.

TheUndeadFish
  • 8,058
  • 1
  • 23
  • 17
  • 2
    Removing `#include "PlayState.h"` worked. PlayState declares Player, but Player also declares PlayState so the line wasn't needed. Thanks. – Greg Treleaven Jul 13 '14 at 19:05
11

I have got through the similar problem and I out solution and made it a thumb rule for me

Solution / Thumb Rule

//File - Foo.h
#include "Child.h"
class Foo 
{
//Do nothing 
};

//File - Parent.h
#include "Child.h" // wrong
#include "Foo.h"   // wrong because this indirectly 
                   //contain "Child.h" (That is what is your condition)
class Parent 
{
//Do nothing 
Child ChildObj ;   //one piece of advice try avoiding the object of child in parent 
                   //and if you want to do then there are diff way to achieve it   
};

//File - Child.h
#include "Parent.h"
class Child::public Parent 
{
//Do nothing 
};

Don't include the child in parent class .

if you want to know the way to have a child object in a parent class the refer the link Alternative

Thank you

Community
  • 1
  • 1
hemant c
  • 157
  • 1
  • 3
1

I know this is not the best way to deal with that problem, but it work for me at least. you can put all your other includes in the cpp file:

#include "OmiGame/OmiGame.h"
#include "PlayState.h"
#include "Mob.h"
#include "resources.h"
Mark green
  • 43
  • 9
0

Just had the same issue. @TheUndeadFish's answer was a great help, but it took me a while to find the root cause. I'd share below a sample scenario that causes this issue and steps I performed to track it down.

So let's assume we have three simple classes:

// a.h
#pragma once
#include "b.h"
#include "c.h"

class b;
class c;

class a {
    b* field_b;
    c* field_c;
public:
    a();
};

a depends on b and c.

// b.h
#pragma once
#include "a.h"

class a;

class b {
    a* field_a;
public:
    b();
};

b circularly depends on a (I'm solving that with forward declaration).

// c.h
#pragma once
#include "b.h"

class c : public b {
public:
    c();
};

c derives from b.

The implementation files are very simple as well (only for the sake of simplicity I'm putting all of them in a single block, but keep in mind that those are three separate files):

// a.cpp
#include "a.h"
a::a() { }
// b.cpp
#include "b.h"
b::b() { }
// c.cpp
#include "c.h"
c::c() { }

Now add them to your project, try to compile, and you'll get something similar to the following error (I'm using Visual Studio):

1>Z:\test\c.h(6,20): error C2504: 'b': base class undefined

So we already know that the problem lies in a fact that in a particular compilation unit compiler sees the child class before it sees the parent class.
How can we prove that? The simplest approach will be to use the message pragma.
I've added two messages inside each of the header files, one at the top (before all the include directives) and another one right before the class definition. For example, this is how c.h now looks like:

#pragma once
#pragma message("Top in: " __FILE__)
#include "b.h"

#pragma message("Before class in: " __FILE__)
class c : public b {
public:
    c();
};

Rebuilding the project will show the following output:

Rebuild started...
1>------ Rebuild All started: Project: test, Configuration: Debug x64 ------
1>a.cpp
// redacted..
1>b.cpp
1>Top in: Z:\test\b.h
1>Top in: Z:\test\a.h
1>Top in: Z:\test\c.h
1>Before class in: Z:\test\c.h
1>Z:\test\c.h(6,20): error C2504: 'b': base class undefined
1>Before class in: Z:\test\a.h
1>Before class in: Z:\test\b.h
1>c.cpp
// redacted..
1>Generating Code...
1>Done building project "test.vcxproj" -- FAILED.
========== Rebuild All: 0 succeeded, 1 failed, 0 skipped ==========

Please note that b.cpp's compilation unit (in bold) fails, and we see where exactly and why: compiler sees the c's class definition before it sees b's class definition.
A simple fix here will be to move the #include "a.h" directive from b.h into b.cpp. Rebuild the project, and this time the compiler will see the class definitions in a desired order:

Rebuild started...
1>------ Rebuild All started: Project: test, Configuration: Debug x64 ------
1>a.cpp
// redacted
1>b.cpp
1>Top in: Z:\test\b.h
1>Before class in: Z:\test\b.h
1>Top in: Z:\test\a.h
1>Top in: Z:\test\c.h
1>Before class in: Z:\test\c.h
1>Before class in: Z:\test\a.h
1>c.cpp
// redacted
1>Generating Code...
1>test.vcxproj -> test.exe
========== Rebuild All: 1 succeeded, 0 failed, 0 skipped ==========

Alex Lipov
  • 13,503
  • 5
  • 64
  • 87