Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Splitting up source into different .cpp and .h files

This thread is locked; no one can reply to it. rss feed Print
Splitting up source into different .cpp and .h files
Felix-The-Ghost
Member #9,729
April 2008
avatar

Hi all,

This is a topic I've attempted to learn time and time again.
I've even had OnlineCop "fix" one of my code projects before so it was "correct."

I have been coding with all my code in one long file instead of multiple focused files (like I want) But splitting up my code is hard for me to grasp how to do, for some reason. I don't think I'm completely stupid, but I think I should have gotten this like a long time ago...

I'm trying to learn it from this article

The way I've written my functions requires variables known across source files (global variables, I guess, which I'm told are bad) I'm having trouble implementing this part of the article:

Quote:

For convenience, some people like to put all the 'extern' declarations into a globals.h file, and all the actual definitions into a globals.cpp file.

When I use externs it says the variables were never defined, when I don't, it says I've declared them more than once.

I use global variables cause I like having functions that already know about other variables so I can do stuff like

void new_game()
{
    TheHead.x = Buffer->w/2;
    TheHead.y = Buffer->h/2;

    TheBody.clear();
    AllFood.clear();

    score = 0;
    mult = 1;
    combo = 0;

    game_loop = 0;
}

instead of

void new_game(head* h, vector <int>* b, vector <int>* f, int* s, int* m, int* c, int* g_l)
{
    h.x = Buffer->w/2;
    h.y = Buffer->h/2;

    b.clear();
    f.clear();

    s = 0;
    m = 1;
    c = 0;

    g_l = 0;
}

I realize the code above probably does not even work (I need to re-learn pointers syntax every so often) But is that how I should write my code (passing pointers to variables into them so they don't have to know about them already)?

Cause I just kinda like how new_game(); looks as opposed to

new_game(&TheHead, &TheBody, &AllFood, &score, &mult, &combo, &g_l);

Although I do realize the latter is probably more "reusable."

I'm honestly having trouble learning this so please don't make fun of me or tell me to RTFM or JFGI or kill myself/delete system32.

I hope this post makes sense 'cause I have a headache now :-/

How do you guys split up your functions, initializations, declarations, etc?

Currently I'm stuck at

1 header file with extern declarations
1 main cpp file including the header
1 functions cpp file including the header
1 globals cpp file with the variable declarations (not extern) including the header

:(

==========================
<--- The ghost with the most!
---------------------------
[Website] [Youtube]

amber
Member #6,783
January 2006
avatar

I like having functions that already know about other variables

From your use of STL vectors, it seems like you're using C++, but you're not using one of the most useful parts of C++. ;)

You should probably read up on object-oriented programming because it seems like you'd benefit a lot from it. Basically, a function that is a member of a class will know about variables that have been declared as part of that class.

For example, you could make a class like:

class GameData {
  int state;
  int money;
  int player_alive;
  // and so on

  public:
  void newgame();
};

You can write your newgame function like:

void GameData::newgame() {
   state = 0;
   money = 100;
   player_alive = 1;
   // or whatever
}

See how it already knows about all of the variables you've declared inside of the class. ;D

Somewhere (you can even do it globally if you want) create an object, i.e., an instance of the class, like this:
GameData game;

Then you can just do game.newgame() like you want to.

This is just a brief (and probably not too useful) introduction, but it should at least point out the concepts you can read more about. Once you've got these ideas down, it becomes easier to break your program across files, because you can do things like put each class in its own file, or the like.

gnolam
Member #2,030
March 2002
avatar

foo.cpp#SelectExpand
1#include "bar.h" 2 3void some_function(void) 4{ 5 some_global++; 6}

bar.h#SelectExpand
1#ifndef BAR_H 2#define BAR_H 3 4extern int some_global; 5 6#endif

bar.cpp#SelectExpand
1int some_global = 666;

(I'll leave it to someone else to explain why globals are considered harmful, why the void new_game() example you gave is hard to follow and unmaintainable, and why you should be using OOP.)

[EDIT]
Ninja'd.

--
Move to the Democratic People's Republic of Vivendi Universal (formerly known as Sweden) - officially democracy- and privacy-free since 2008-06-18!

Felix-The-Ghost
Member #9,729
April 2008
avatar

I've used classes before in other projects, and I thought about putting like everything into one class or struct but I wondered if that would be another "bad practice." I read somewhere about "encapsulating globals into a class" or something which is what I think you're talking about.

I guess the prefix "class_name::" isn't nearly as bad as passing variables directly into a function.

Thanks, I think I know enough to try that idea soon. Although I need to look in my old projects how I did class definitions. Am I gonna need an external declaration, too? At least it'd be one with everything in it.

==========================
<--- The ghost with the most!
---------------------------
[Website] [Youtube]

David Sopala
Member #5,056
September 2004

It takes some thinking sometimes... Think of something like an [item] in a game now we have different flavors of [item]s like [weapon]s, [armor]s, [metal]s, and whathaveyou. So something like that you might have a class called item and a few more classes that are all items so they would inherit from item.

So you can have something like

player->use_item(item myitem);

global variables can be accessed by everyone everywhere - this leads to problems when you get deeper into coding. Especially when you have multiple people working on a project guy 1 changes something that breaks guy 2's code all kinds of weirdness.

Don't think of classes as containers; think of them as though you were building an actual game in front of you. You might want a wall and who knows bricks in the wall even - depending on what can happen to said wall...

I will say this currently in the server I am writing I have around 24 files, but my main source file is only 240 lines long. Classes help alot and once you understand them you will ask how you ever did stuff without them.

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

I realize the code above probably does not even work (I need to re-learn pointers syntax every so often) But is that how I should write my code (passing pointers to variables into them so they don't have to know about them already)?

You didn't access the pointers properly. You need to use -> to access members and methods, and you need to use * to access the data pointed to by a pointer.

I've used classes before in other projects, and I thought about putting like everything into one class or struct but I wondered if that would be another "bad practice." I read somewhere about "encapsulating globals into a class" or something which is what I think you're talking about.

Smashing everything into a single class is not what you want to do. That's the same thing as putting everything into a single main.cpp file. You need to logically organize related data using structs or classes. Using your original example, this would be an improvement :

Using structs :

#SelectExpand
1typedef struct Game { 2 head h; 3 vector<int> b; 4 vector<int> f; 5 int s; 6 int m; 7 int c; 8 int g_l; 9}; 10 11void new_game(Game* g); 12 13int main(int argc , char** argv) { 14 Game g; 15 new_game(&g); 16 return 0; 17} 18 19void new_game(Game* g) 20{ 21 g->h.x = Buffer->w/2; 22 g->h.y = Buffer->h/2; 23 24 g->b.clear(); 25 g->f.clear(); 26 27 g->s = 0; 28 g->m = 1; 29 g->c = 0; 30 31 g->g_l = 0; 32}

Now to organize your source and header files, you would put the Game struct declaration in a header file by itself (Game.h) along with the prototype for new_game. Then you would put the definition for new_game into Game.c. After that you would include Game.h in main.c. Now everything is logically organized.

bamccaig
Member #7,536
July 2006
avatar

Felix-The-Ghost
Member #9,729
April 2008
avatar

It's just weird thinking of the game as an object :P

==========================
<--- The ghost with the most!
---------------------------
[Website] [Youtube]

bamccaig
Member #7,536
July 2006
avatar

It's just weird thinking of the game as an object :P

A "game" is a noun, and therefore an object. ;) The program is also an object. Whether or not it's useful to think of them as such in code is up to you. Rather than just having 30 variables in a single "game" class, you could instead decide to split each variable up into a logical class. If you want you can probably describe your game to us and the main global variables that you do have and get some help from people here with modelling that. Conceptually, a single game class with all of the program's functions as methods of it accessing all of the program's state through member variables is identical to a program with global variables and free functions. :P That doesn't solve anything!

Felix-The-Ghost
Member #9,729
April 2008
avatar

Well when I think of "object" I usually think of material, tangible things (Or things that would be tangible outside the software).

I understand a class of tank or bullet but it's new to me to have the program itself be an "object". But I do understand why it works now. I haven't had time to try to implement it yet. I guess I could use a struct for non-"tangible" things if I were to be really anal about it (aren't structs and classes functionally the same in C++?)

==========================
<--- The ghost with the most!
---------------------------
[Website] [Youtube]

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

David Couzelis
Member #10,079
August 2008
avatar

"I do realize the latter is probably more reusable."

My advice is to simply program it the way that makes it easier for you to understand. Don't waste time making code more reusable, because you're never going to reuse it.

If you're working on a project some time in the future and you DO want to reuse it, THAT'S when you make it reusable.

Go to: