Splitting up project in .h and .cpp

Started by
15 comments, last by c4c0d3m0n 16 years ago
I must say I still don't quite understand how to manage my code in the correct files. My code doesn't do anything yet, I just started this project, but I want to organize my files correctly from the start on. This is how I've tried it untill now: main.cpp
/**
  * PongSDL
  * Reinventing the wheel
  *
**/

#include <cstdlib>

#include "graphics.h"


int main ( int argc, char* argv[] )
{
    Gfx gfx;
    gfx.init();

    return 0;
}

/**
  * End of main.cpp
  *
**/

graphics.h
/**
  * graphics.h
  *
**/


class Gfx
{
public:

    Gfx();
    ~Gfx();

    int init();

    int draw();

private:

    SDL_Surface* screen;

};



/**
  * End of graphics.h
  *
**/

graphics.cpp
/**
  * graphics.cpp
  *
**/


#include "graphics.h"

#include <SDL/SDL.h>


const int GFX_SCREEN_W = 600;
const int GFX_SCREEN_H = 400;


Gfx::Gfx()
{
    *screen = NULL;
}

Gfx::~Gfx()
{
    SDL_FreeSurface( screen );
}


int Gfx::init()
{
    if ( SDL_Init( SDL_INIT_VIDEO ) < 0 )
    {
        printf( "Unable to init SDL: %s\n", SDL_GetError() );
        return -1;
    }

    SDL_WM_SetCaption( "PongSDL", NULL );

    *screen = SDL_SetVideoMode( GFX_SCREEN_W, GFX_SCREEN_H, 32, SDL_SWSURFACE );

    if ( !screensurface )
    {
        printf( "Unable to set video: %s\n", SDL_GetError() );
        return -1;
    }

    return 1;
}



/**
  * End of graphics.cpp
  *
**/

The error:
graphics.h:20: error: ISO C++ forbids declaration of `SDL_Surface' with no type
graphics.h:20: error: expected `;' before '*' token
Can someone tell me how to organize my files properly? Thanks. PS: I'm using CPP, but for some reason GameDev gets rid of the two plusses in my post.
Advertisement
You need to #include <SDL/SDL.h> in your graphics.h header.
Your graphics.h has no way of knowing what SDL_Surface means. To fix the problem, you should move the inclusion of SDL.h to the beginning of graphics.h.

File inclusion in C/C++ has some quirks though, for which reason you should really use include guards. It's very simple, really. Just do the following:
// blarg.h// Class that does awesome stuff#ifndef BLARG_H#define BLARG_H// Your code and includes goes here#include <SDL.h>class Blarg {    // Stuff};#endif // BLARG_H


This ensures that your code is only parsed once, no matter how many times the file is included from the same compilation unit.
That error occurs in your graphics.cpp file, when you include #include "graphics.h". You are doing that before including #include <SDL/SDL.h>, so when it sees SDL_Surface, it doesn't know what it is.

You should include the standard includes before your own headers, like you've correctly done in main.cpp.

So your graphics.cpp file should look like:
/**  * graphics.cpp  ***/#include <SDL/SDL.h>#include "graphics.h"...
I suggest you read this article if you haven't already. It may not be the best, but it's the only one I know of.

http://www.gamedev.net/reference/articles/article1798.asp
You need to put #include <SDL/SDL.h> into the beginning graphics.h, because you refer to types defined there. Also, you should add guards to your header files.

Put this right into the beginning of graphics.h, before anything else:
#ifndef GRAPHICS_H#define GRAPHICS_H


And this comes right at the end after everything else:
#endif // GRAPHICS_H


If you do not have these guards, and you include graphics.h twice, the compiler will complain of doubly defined classes and such.
Including SDL in the header file solved my problem.
Including SDL before the header in the cpp file did not solve my problem. I chose to just include it in the header aswell.
Thanks a lot for the tips on the guards, this will probably save me lots of trouble later on.
I remember seeing that article somewhere sometime, but I couldn't fid it anymore. I bookmarked it this time :)

Thanks for all your replies
I still have many problems... Google made me a little wisers and taught me how to use the extern operator, but it doesn't always work.

snippet of game.h
/**  * game.h  ***/#ifndef GAME_H#define GAME_H#include "graphics.h" // The game passes commands to the graphics#include <SDL/SDL.h> // For SDL_Event#include "ball.h" // The game has a ball#include <vector> // Sometimes more than one ball// ...struct Gamestate{public:    std::vector<Ball> vball;};// ...#endif // GAME_H

snippet of graphics.h
/**  * graphics.h  ***/#ifndef GFX_H#define GFX_H#include <SDL/SDL.h> // For SDL_Video#include "game.h" // Needs information about game elements to draw// ...class Gfx{public:    Gfx();    ~Gfx();    int init();    void draw( Gamestate* state ); // <- Error is hereprivate:    SDL_Surface* screen;    void drawPixel( int x, int y );};// ...#endif // GFX_H


I get the following error:
graphics.h:24: error: `Gamestate' has not been declaredgraphics.h:24: error: ISO C++ forbids declaration of `state' with no typegraphics.h:24: note: candidates are: void Gfx::draw(int*)


I can't use the extern keyword for struct though! What am I doing wrong?
Here you need a forward declaration. See the section "Fixing Problem 2" in the above article.
Hmmm, this is going very wrong already... I don't understand the idea behind proper splitting up of files. I started programming Pong to teach myself this. Could you please look at my code and tell me how I should split things up and what needs to include what with a little explanation. Thanks in forward

main.cpp
/**  * PongSDL  * main.cpp  ***/#include "game.h"int main ( int argc, char* argv[] ){    Game pong;    if( pong.mainMenu() )      pong.play();    pong.~Game();    return 0;}/**  * End of main.cpp  ***/

game.h
/**  * game.h  ***/#ifndef GAME_H#define GAME_H#include <SDL/SDL.h> // For SDL_Event#include "graphics.h" // We need some graphics to play#include "ball.h" // The game has a ballstruct Gamestate{public:    Ball ball;};class Game{public:    Game();    ~Game();    bool mainMenu();    int play();private:    Gfx gfx;    SDL_Event event;    Gamestate* current_state;    Gamestate* previous_state;};extern Ball newBall( int x, int y, float velocity, float angle, float rad );extern void updateBall( Ball* b, double dt );#endif // GAME_H/**  * game.h  ***/

game.cpp
/**  * game.cpp  ***/#include "game.h"#include <SDL/SDL.h> // For SDL_Event#include "timer.h"#include "ball.h"void process( Gamestate* state, double t, double dt ){    // Move ball    updateBall( &state->ball, dt );    // Todo: Rest of processing, eg. collision detection}Game::Game(){    gfx.init();}Game::~Game(){    gfx.~Gfx();}bool Game::mainMenu(){    return true;    // Placeholder for a future main menu}int Game::play(){    Timer timer;    const float DELTA = 0.01;    previous_state = new Gamestate;    current_state = new Gamestate;    current_state->ball = newBall( 100, 100, 0.1, 0.0, 5.0 );    bool loop = true;    while( loop ) {        timer.fillAccu();        while( timer.pinchAccu( DELTA ) ) {            // Process here            *previous_state = *current_state;            process( current_state, timer.getTimePassed(), DELTA );        } // End of processing        while( SDL_PollEvent( &event ) ) {            if( event.type == SDL_QUIT )              loop = false;        } // End of event polling        gfx.draw( current_state );    } // End of main loop    return 0;}/**  * End of game.cpp  ***/

graphics.h
/**  * graphics.h  ***/#ifndef GFX_H#define GFX_H#include <SDL/SDL.h> // For SDL_Videostruct Gamestate; // Forward declarationclass Gfx{public:    Gfx();    ~Gfx();    int init();    void draw( Gamestate* state );private:    SDL_Surface* screen;    void drawPixel( int x, int y );};const int GFX_SCREEN_W = 600;const int GFX_SCREEN_H = 400;#endif // GFX_H/**  * End of graphics.h  ***/

graphics.cpp
/**  * graphics.cpp  ***/#include "graphics.h"#include <SDL/SDL.h> // For SDL_Video#include "game.h" // To interact with game elements#include <math.h> // For sqrt()Gfx::Gfx(){    screen = 0;}Gfx::~Gfx(){    SDL_FreeSurface( screen );}int Gfx::init(){    if( SDL_Init( SDL_INIT_VIDEO ) < 0 )    {        printf( "Unable to init SDL: %s\n", SDL_GetError() );        return -1;    }    SDL_WM_SetCaption( "PongSDL", NULL );    screen = SDL_SetVideoMode( GFX_SCREEN_W, GFX_SCREEN_H, 32, SDL_SWSURFACE );    if( !screen )    {        printf( "Unable to set video: %s\n", SDL_GetError() );        return -1;    }    return 1;}void Gfx::draw( Gamestate* state ){    // WIP}void Gfx::drawPixel( int x, int y ){    SDL_Rect rect;	rect.x = x;	rect.y = y;	rect.w = 1;	rect.h = 1;	SDL_FillRect( screen, &rect, SDL_MapRGB( screen->format, 0xFF, 0xFF, 0xFF ) );}/**  * End of graphics.cpp  ***/

timer.h
/**  * timer.h  ***/#ifndef TIME_H#define TIME_H// Time is measured in secondsclass Timer{public:    Timer();    //~Timer();    void fillAccu();    bool pinchAccu( float dt );    float getTimePassed();private:    float time_passed;    float current_time;    float accumulator;    float new_time;    float delta_time;};#endif // TIME_H/**  * End of timer.h  ***/

timer.cpp
/**  * timer.cpp  ***/#include "timer.h"#include <SDL/SDL.h> // For SDL_GetTicks()Timer::Timer(): time_passed(0.00),  accumulator(0.00),  new_time(0.00),  delta_time(0.00){    current_time = (float)SDL_GetTicks() / 100;}void Timer::fillAccu(){    new_time = (float)SDL_GetTicks() / 100;    delta_time = new_time - current_time;    current_time = new_time;    accumulator+= delta_time;}bool Timer::pinchAccu( float dt ){    if( accumulator >= dt ) {        time_passed+= dt;        accumulator-=dt;        return true;    }    return false;}float Timer::getTimePassed(){    return time_passed;}/**  * End of timer.cpp  ***/

ball.h
/**  * ball.h  ***/#ifndef BALL_H#define BALL_Hstruct Ball{public:    float x;    float y;    float velx;    float vely;    float r;};#endif // BALL_H/**  * End of ball.h  ***/

ball.cpp
/**  * ball.cpp  ***/#include "ball.h"#include "math.h"Ball newBall( int x, int y, float velocity, float angle, float radius ){    Ball b;    b.x = x;    b.y = y;    // Set velocities in px/s.    // 180.0*3.14 converts the angle from ° into rad    b.velx = velocity * cos( angle / 180.0 * 3.14 );    b.vely = velocity * sin( angle / 180.0 * 3.14 );    b.r = radius;    return b;}void updateBall( Ball* b, double dt ){    b->x+= dt * b->velx;    b->y+= dt * b->vely;}/**  * End of ball.cpp  ***/
It's not usually a good idea to split up code unless you need to. Well organised code is a balance - 3000 line main files makes people cry, but having 20 or so files makes for irritating reading.

What error is your program kicking up? It might be a good idea to start with everything in main.cpp then just build up extra .h/.cpp files one at a time as needed (thats how I program anyway, and when it's just a one man project that tends to work fine).

'Picturing' a whole system of interconnected files and objects before implimenting it can be a whole job in itself (I think thats what software archietects do, but don't quote me on that), and when your task doesn't require you to do it, don't bother! Just take little steps. If it's something reasonably straightforward like pong maybe you coudl write it all in main(), then move components out into other files once you see groupings of functions or objects that can be put together logically.

This topic is closed to new replies.

Advertisement