views:

160

answers:

3

I have a program using 3 header files and 3 .cpp files in addition to main.cpp. I'm using VC++ 2008.

Here's the setup. All three headers are guarded with #ifndef HEADERNAME_H, etc. Also all three headers have corresponding .cpp files, which #include their respective headers.

/* main.cpp */
    #include "mainHeader.h"

/* mainHeader.h */
    #include <windows.h>
    #include <iostream>
    //Others...
    #include "Moo.h"   

/* Moo.h */
    #include "mainHeader.h"
    #include "Foo.h"

    class Moo {
        private:
        int varA;
        Foo myFoo1;
        Foo myFoo2;
        Foo myFoo3; 

        Public:
        void setVarA(int);    // defined in Moo.cpp
        //etc
    };

/* Foo.h */
   #include "mainHeader.h"
   class Foo { ... };

I'm getting compiler errors for instantiating the three Foo's inside of Moo.h:

error C2079: 'Moo::setVarA' uses undefined class 'Foo'

I included Foo.h right there, so why is it undefined? This is the only file that includes Foo.h. I even tried declaring Foo by placing 'class Foo;' before my declaration of class Moo.

I also have #defines in my Foo.h file that are also causing compiler errors when I use them in Moo.h. (undeclared identifier error C2065).

It seems like Foo.h isn't getting included because Moo.h can't find anything defined/declared in it. What's going on?

My actual code is long, but here you go (it's a mario platformer game btw):

This would be Foo.h:

//**************************
//  Animation.h
//**************************
//  Header to Animation class

#ifndef ANIMATION_H
#define ANIMATION_H

#include "../Headers/MarioGame.h"

#define MAX_ANIMATIONS 58

extern char* fileAnimations[MAX_ANIMATIONS];
extern char marioAnims[MAX_ANIMATIONS][3000];
extern char background [3700000];

class Animation
{
private:
    int imageCount;

public:
    DWORD lastAnimTick;
    int lastAnim;
    int anims[4][2];
    DWORD animsTime[4];

    // Constructor
    Animation();

    // Mutators
    void addImage(int left, int right, DWORD time);
    void defaultAnimation();

    // Accessors
    int getImage(bool facingLeft);
    int getImageCount();
    int getCurLoc();
};

#endif  // ANIMATION_H

This would be "Moo.h." Note the many private Animation members, all causing errors:

//**************************
//  Mario.h
//**************************
//  Header to Mario class

#ifndef MARIO_H
#define MARIO_H

#include "../Headers/MarioGame.h"
#include "../Headers/Animation.h"

enum { MARIO_TYPE_SMALL, 
       MARIO_TYPE_BIG, 
       MARIO_TYPE_LEAF };

class Animation;

class Mario
{
private:
    #pragma region Variable Declarations
     float xPos;
     float yPos;

     float xVel;
     float yVel;

     float lastXVel; //used for determining when walk/run decceleration is complete

     float xAccel;
     float yAccel;

     float xSize;
     float ySize;

     float halfW;
     float halfH;

     bool grounded;
     bool walking;
     bool running;
     bool pRunning;
     bool jumping;
     bool hunching;
     bool gliding;
     bool flying;
     bool decelerating;
     int facing;

     DWORD pRunTimer;
     int pChargeLevel;

     DWORD jumpStart;

     DWORD glideStart;

     int type;

     bool updateXMovement;
     bool updateYMovement;

     bool screenUpLock;

     char marioAnims[MAX_ANIMATIONS][3000];

     Animation smallStand;
     Animation smallWalk;
     Animation smallRun;
     Animation smallPRun;
     Animation smallJump;
     Animation smallSkid;

     Animation bigStand;
     Animation bigWalk;
     Animation bigRun;
     Animation bigPRun;
     Animation bigJump;
     Animation bigSkid;
     Animation bigHunch;

     Animation leafStand;
     Animation leafWalk;
     Animation leafRun;
     Animation leafPRun;
     Animation leafJump;
     Animation leafSkid;
     Animation leafHunch;
     Animation leafTailWhack;
     Animation leafGlide;
     Animation leafFly;
     Animation leafFalling;

     Animation* lastAnim;
    #pragma endregion

public:
    //Constructor
    Mario();

    //Mutators
    void setGlideStart( DWORD g );
    void setHunching( bool h );
    void setGliding( bool g );
    void setFlying( bool f );
    void setType( int t );
    void setPChargeLevel( int c );
    void setPRunTimer( DWORD t );
    void setScreenUpLock( bool s );
    void setUpdateXMovement( bool m );
    void setUpdateYMovement( bool m );
    void setDecelerating( bool d );
    void setPos( float x, float y );
    void setVel( float x, float y );
    void setAccel( float x, float y );
    void setSize( float x, float y );
    void setJumping( bool j );
    void setJumpStart( DWORD s );
    void setGrounded( bool g );
    void setWalking( bool w );
    void setRunning( bool r );
    void setPRunning( bool r );
    void setLastXVel( float l );
    void setFacing( int f );
    void defaultAnimations();

    //Accessors
    DWORD getGlideStart();
    bool getHunching();
    bool getGliding();
    bool getFlying();
    int getType();
    int getPChargeLevel();
    DWORD getPRunTimer();
    bool getScreenUpLock();
    bool getUpdateXMovement();
    bool getUpdateYMovement();
    bool getDecelerating();
    float getXPos();
    float getYPos();
    float getXVel();
    float getYVel();
    float getXAccel();
    float getYAccel();
    bool getJumping();
    DWORD getJumpStart();
    float getXSize();
    float getYSize();
    float getHalfW();
    float getHalfH();
    bool getGrounded();
    bool getWalking();
    bool getRunning();
    bool getPRunning();
    float getLastXVel();
    int getFacing();
    int getAnimation();
};

#endif  // MARIO_H

This would be "mainHeader.h":

//**************************
//  MarioGame.h
//**************************
//  Header to MarioGame functions
//  Contains Includes, Defines, Function Declarations, Namespaces for program

#ifndef MARIOGAME_H
#define MARIOGAME_H

//*=====================
//  Defines
//*=====================
#define WINDOWED     0     // predefined flags for initialization
#define FULLSCREEN   1

#define WNDCLASSNAME    "MarioGame"   // window class name
#define WNDNAME   "Mario Game"  // string that will appear in the title bar

#define NUM_OF_KEYS  5
#define KEY_SPACE       0
#define KEY_UP          1
#define KEY_DOWN        2
#define KEY_RIGHT       3
#define KEY_LEFT        4
#define KEY_CONTROL  5

#define GRIDW     2.0f
#define GRIDH     2.0f

#define PATHING_SIZE 33

//*=====================
//  Includes
//*=====================
#include <windows.h>

#include <gl/gl.h>
#include <gl/glu.h>

#include <iostream>
#include <fstream>
#include <vector>
#include <math.h>
#include <WAVEMIX.H>

#include "../Console/guicon.h"
#include "../Headers/Mario.h"



//*=====================
//  Function Declarations
//*=====================
LRESULT CALLBACK WinProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
HWND createWindow(HINSTANCE &hinst, int width, int height, int depth);

void renderFrame();
void think();
void loadTextures();
void WMInit(HINSTANCE, HWND);

void resize (int width, int height);
void shutdown();

void keyLeft(bool);
void keyRight(bool);
void keySpace(bool);
void keyDownArrow(bool);

bool checkBoundary(float, float);
void onPlayerDeath();

class Mario;

//*=====================
//  Namespaces
//*=====================

using namespace std;

//*=====================
//  Global Variable Declarations
//*=====================
extern Mario Player;

extern HDC hdc;
extern HGLRC hglrc;
extern HWND hwnd;

extern int SCRW;
extern int SCRH;
extern int SCRD;

extern DWORD oldTick;
extern DWORD oldTick2;
extern DWORD oldPTime;

extern float pixelZoom;

extern float screenPosX;
extern float screenPosY;     

extern float playerScrollMultiplier;    

extern float playerTerminalWalkVel;
extern float playerWalkAccel;    

extern float playerRunAccel;      
extern float playerTerminalRunVel;

extern float playerDecel;   

extern float playerPVel;
extern DWORD playerPRunAchieveTime;  

extern float playerJumpUpVel;   
extern float playerJumpTime;

extern float gravityAccel;  
extern float playerTerminalFallVel; 

extern float playerTerminalGlideFallVel;


extern bool keyDown[NUM_OF_KEYS];
extern bool lastSpace;    

extern bool drawPathingMap;    

extern float pathing [PATHING_SIZE][5][2];   

#endif    // MARIOGAME_H

Here's main.cpp:

//**************************
//  main.cpp
//**************************
// Primary implementation file; handles Win32 interface 


#include "../Headers/MarioGame.h"
//*=====================
//  WinMain
//*=====================
int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE hprevinstance, LPSTR lpcmdline, int nshowcmd)
{
    ...
}

//And other functions....
+2  A: 

You need a forward declaration for class Foo. For more information refer to item 31 of "Effective C++, Third Edition". Note: if you forward declare Foo that means your class Moo will only be able to have pointers of type Foo.

If something includes Foo.h this is what happens (the arrows show dependency):

Foo.h --includes--> mainHeader.h --includes--> Moo.h --includes--> Foo.h

Note that when class Moo is specified the second Foo.h is not included due to your guards, also class Foo has not been declared yet because that happens after including mainheader.h

Trent
First, is it possible to do this without forward declaration and without pointers, but actual classes?Second, what about a #define in Foo.h that is not found by Moo.h???
Tony R
If you are able to ensure that Foo.h is ALWAYS included before Moo.h you shouldn't have a problem. Your example only shows Moo.h including Foo.h, but I don't think this is the case. As others have suggested you should post a more complete example that fails.
Trent
Thank a bunch, you saw the problem, but it took the preprocessor dump file (thanks Dan Olsen) for me to see it.
Tony R
+2  A: 

The best tool for debugging these sorts of situations is the compiler's "dump preprocessed output to a file" option. If you enable this, you'll most likely see the problem right away. Check your compiler options for how to enable it.

Dan Olson
Great tip, this helped me see the problem.
Tony R
A: 

Another problem to watch out for is the use of 'using namespace' statements - you should not use these in header files at all.

This is to avoid ambiguities for modules that include lots of different header files.

So, yes, without it you will need to do lots of std::vector, std::list etc which can be a pain.

quamrana