by Jay Bernardo
jay(at)loomsoft(dot)net

Before we begin at all...
This tutorial is part of the LoomSoft resources section. It has been created for public viewing and that only. All materials are copyright© 2002 by LoomSoft. You may not use, reproduce, or distribute this or any other linked files without permission.

Web: http://www.loomsoft.net
Email: jay(at)loomsoft(dot)net

Disclaimer and Pre-Article stuffs.

Okay, this tutorial is (hopefully) all about organizing your project; making it easier to navigate; making your life more sane while you code. Please remember, I've written this in my free time by myself. These are my general ideas and opinions on how to go about organizing all your stuff to make things play nice. By no means am I the "almighty seer of truth." :) These are just the methods that I use and know work for me. If they work for you, too, then hooray! I'll try to use images and screenshots as much as possible if it would help to explain a key point or idea. If anything it still unclear, just email me and I'll patch up my article. See the end of the article for contact information and the such.

It is assumed that you have some skills with coding, as I will refer to such things as classes, functions, variables, etc.

Also note that I use Microsoft Visual C++ (MSVC) [version 6.0 {standard} if that's of any use to anyone]. This article will probably refer some stuff that's MSVC specific, so don't get upset when you see it! :)

Contents

1. Why we want, and what it means to organize your project
2. Naming Files
3. Separating Code into Multiple Files (Theory)
4. Separating Code into Multiple Files (Method)
4a. Separating using the keyword extern
4b. Separating using header files
5. Classes and header files
6. Summing it up
7. End Notes


1. Why we want, and what it means to organize your project (this is basicallly just to get you thinking in the right "direction")

I think it's safe to assume that at some point in all of our programming careers we've seen, or have even created games (or general programs) that were just a single source file. I'm not talking about the simple "Hello World" programs, either. I'm talking about bigger programs where each function, class, variable, pointer (you name it, it was in that file) was all declared within a single file. Unless you have memorized the name of each and every function you have created, it will be a pain to find what you're looking for while programming. Of course, there are visual tools that will list all functions within a file, but this too can be tedious if you have hundreds or even thousands of functions or declarations in your program.

What we do to fix projects like this is organize them. Let me give you a definition that works in terms of this article. If your project is organized it will have: multiple files in which each file contains a central location for a specific type of data and or functions which serve a general purpose, or work together to perform this general task. Was that clear? Basically you want a seperate file for each different type of "stuff" you're doing.


2. Naming files

Let's talk about the file names of an organized project. To the right is a screenshot (actually, 2) of the MSVC workspace from my current project Zep's Dreamland. You may be wondering why I have so many different files! Well, this is my own preference on how to organize my programs. I divide everything as much as possible into separate files that do all my different types of "stuff." We will talk more about this in another section, however.

The first thing I would ask you to notice is not the number of files, but the names of the files. This is important when organizing your code. Each time you create a new file for that "central location" of data, you will want to name it correctly. This allows for you to be able to find what you are looking for much quicker. Now seriously take a look at the names of my files. If you don't know anything about the game, some file may not make sense, but take a look at the more general named ones like: screenshot.cpp, randomize,cpp, load_music.cpp, etc. You can easily imagine what kinds of functions and variables are contained within each file:
screenshot.cpp contains anything having to do with taking/processing a screenshot.
randomize.cpp contains anything having to do with generating random numbers.
load_music.cpp contains anything having to do with preparing/loading music files

Note how easy it is to take a quick look at a specific list of files and be able to efficiently determine what kinds of functions and data are contained within. This is a major step in organizing your code. Think of names that are easy for you to understand, and quite possibly even easier for others to understand; especially if your project is opensource, or is being worked on in a team. If your file names are easy for others to read and quickly understand chances are it will be the same for you as well.

Naming files can be tricky, however. It can lead to potiential problems such as simply having to rename the file later on due to the fact that it could be more generalized. This isn't really a big problem, though. It isn't very difficult to simply rename a file :) Just thought I would warn you, though!

Examples

You have just created a file which contains functions that scroll text across the screen.
You should call it something like:
- text_scroller.cpp
- scroll_text.cpp
- scrolling_text.cpp

You should not call it something like:
- t.cpp
- ts.cpp
- sp.cpp

As you can see, I've gone overboard and used pretty ambigiuous names for the "not" section, but I hope that gets the point across. Even when dealing with functions that process a lot of things like say:

You have a file which contains functions that scroll a map, save minimaps of the map, and draws the map to the screen.

The most simple and easy to understand filename to choose would simply be
- map.cpp, or
- map_routines.cpp

Instead of something like
- map_minimap_draw.cpp
which can just be very misleading.

Try to stay simple, and down to the point. Ask yourself, "what is this file for?" It will most likely reveal the answer. In the first example, the answer would be "to scroll text." For the second example it's a little more complicated, but if you think about it the answer would be "to process maps," or "to do maps." As you can see, the filenames are usually taken directly from the answer to this question. There are other methods, but I find this works quite well. It is kind of an automatic process, and you don't even really realize that you are asking yourself this question.

Back To Contents

3. Separating Code into Multiple Files (Theory)

Alright, so now you've got the lowdown on how to name your files--but I haven't said anything yet which would lead you to have to name more than a single file! So.. here it is!

How do you detemine just when to separate one file into two or more nicely named (see section 2) files? As I've mentioned in section one. If your program consists of many classes, functions, variable declarations, etc., all contained within one file this is definitely a good candidate for separation.

When figuring out how to separate just think of the simplest way. If you have a group of functions that work together to perform a general task you may be better off separating it into it's own file. Consider even a single function that it quite lengthy, but only performs one single action. Take a logical and drawing routine for instance. Most games have a logical part, and a drawing part to them. These sections can often be quite lengthy, so it would seem only logical to separate them into their own functions in separate files. What would we call these files? Something like logical.cpp and drawing.cpp would work. Name them as you like, you know how to do it correctly! Think about how this makes your project more organized. Before this separation, your project consisted of a single file, most likely called game.cpp or main.cpp or something of the like. Hopefully you named it nicely! Now, your project may look like this:

-main.cpp
-logical.cpp
-drawing.cpp

Why is this better? Think of it in terms of speed. When you need to access a specific part of your program, you have three choices. You may think this will slow things down, but it actually doesn't. Instead of searcing one single file for screen drawing stuff, all you need to do is open up drawing.cpp and work on the code within that file. Since all functions and routines contained within that file have to do with drawing there should be no hesitance when choosing that file to edit when you are looking to edit your drawing code. The same would go for logical.cpp, which would contain all of the code having to do with the logical part of the game.

As always, there aren't any real solid rules on when to break up your code beyond this point. It's really up to you. You could contain all your drawing code within drawing.cpp, but I like to take it a step further. Consider this, I have a class called player (which is obviously defined within it's own header/source file). The player has it's own drawing routines. Instead of housing the players drawing routines within the drawing source file, the source file which contains player's declaration would contain player's drawing routines. Why do I do this when drawing.cpp is supposed to contain all drawing code? Well, it's simple. Since player's drawing routines really "belong" to player, the files containing the player definition should also contain the drawing routines. This way, when I think "I need to edit the player's drawing" I will instinctively think that it will be in the player's file, since all and everything having to do with the player is contained within that file. Therefore it is good practice to split things up this way. Furthermore, the actual call to the function that draws the player would be in drawing.cpp.

See how things eventually fall apart? Now the project may look something like this:

-main.cpp
-player.cpp, player.h
-logical.cpp
-drawing.cpp

Drawing.cpp may look like:

void draw_stuff(void)
{
   //All drawing code and routines

 //Some more drawing code and routines....
  player.draw_stuff(void); // The call to the function defined in the player files which draw the player
}


See how it kind of fits together? This can also be done for logical.cpp, where any logical processing functions for the player class would be contained within the player class's separate files, but called from within the logical.cpp file.

Back To Contents

4. Separating code into multiple files (Method)

Alright. Now, there's two different methods we can use to implement the ideas you've just learned about separating your code into multiple files. The two methods are pretty general:

-Using the keyword extern, or
-Using header files.

They both accomplish pretty much the same thing. It's really up to your preference which one you would like to use. You may even create some sort of hybrid where you use both. The explanation of both methods will be done in two separate sections. If you already know about extern and would like to get right into using header files to pseudo-replace extern, then go ahead and skip the extern section. If you don't know either, and are eager to get into using header files, I would recommend reading up on how extern works. Some uses of header files actually require the use of extern! It's to your benefit, especially if you've never encountered it before. Again, I may not explain this in the best possible way. If you truly want to learn the exact and proper use of extern, consult a manual on C++ written by a professional :)

Onto the information!

Back To Contents

4a. Separating using the keyword extern

To explain how extern works, I will use the simplest form possible, and then work up off of that, using examples. Feel free to try out these examples for yourself, as it's through actually doing that you will learn the most! First off, we need the original file, which contains everything in it. Of course, in this example, splitting up such simple code to be "organized" would prove to be pointless when only dealing with a file which contains only two functions and some #includes. Keep in mind that this is just for showing you how things are done.

Here is the original file, called 4a_main.cpp.

#include <iostream.h> //Required header file for i/o streams

void ask_question(void) // A function to ask a question
{
   int age = 0; // Declare an integer called age, which we use to store input
   cout << "What is your age:"; // Out put the question phrase
   cin >> age; // Input the typed in number into the variable age
   cout << "Wow, you're " << age << " years old!" << endl; // Output a nice little message
}

int main() // The main function. This is where the program starts
{
   cout << "Hello world!" << endl; // Output a hello statement
   ask_question(); // Call the function called ask_question.
   return(0);
}

Try it out for yourself. The code should work fine if you copy/paste. (If using MSVC, make sure it's a win32 console program).
Now, lets turn this into two files. One will be 4a_main_2.cpp, and the other will be called ask_question.cpp. As you can see, I've named the file exactly as I've named the function. Even though it doesn't do much, what it does do is ask a question, so I named the file accordingly to what the contents of that file do: which is ask a question.

4a_main_2.cpp

#include <iostream.h> //Required header file for i/o streams


extern void ask_question(void);
// Here is the use of extern. The extern keyword simply tells the program that the actual
                                              // declaration of the function ask_question is located somewhere else, and to use that declaration when
                                              // the function ask_question is called from anywhere in this file. However, extern also has scope, just like
                                              // any other declaration in C++. If you were to move this line to after the { in the function
                                             // main, the program would only be able to call ask_question from within the main function.

int main() // The main function. This is where the program starts
{
   cout << "Hello world!" << endl; // Output a hello statement
   ask_question(); // Call the function called ask_question.
   return(0);
}


ask_question.cpp

#include <iostream.h> // This header file is required for i/o stream processes

void ask_question(void) // A function to ask a question
{
int age = 0; // Declare an integer called age, which we use to store input
cout << "What is your age:"; // Out put the question phrase
cin >> age; // Input the typed in number into the variable age
cout << "Wow, you're " << age << " years old!" << endl; // Output a nice little message
}

Alright, so lets get to explaining things. What exactly did we do? Well, first, we created a file called ask_question.cpp. After we created the file, we copied the complete function called ask_question into that new file, as you can see. We did, however, require one extra line of code which was the #include <iostream.h>. Try compiling without that line in ask_question.cpp. It will not work. Even though the function gets called from another file which has the same header file included, ask_question.cpp still requires that you include the header file. Righteyo. Now that we have the two separate files, it's time to use extern to tell 4a_main_2.cpp that we want to use the function ask_question in ask_question.cpp. It's quite simple. Just use the keyword extern and "declare" the function just you normally would, except without any contents. Also, if the function has any arguments, you do not include the names of the arguments, but just the arguemnt types.
(for instance, if the actual ask_question function was declared as: void ask_question(int number);, the extern line would look like: extern void ask_question(int);)
In the line:
extern void ask_question(void); we have "told" main.cpp where to find the function ask_question.

So, that's how extern works! It's quite simple. You can apply it to functions, classes, variables, anything you want. Experiment with it until you feel comfortable. Next, using header files!

Back To Contents

4b. Separating using header files

A header file works much like extern in the respect that it lets you take things defined in one file and use them in a separate file. It is also much powerful as you can, for instance, have it declare all your externs for you so all you need to do is include the said header file in each file you need to use the externs in instead of having to redeclare the externs each time. Okay, so lets take a look at some important stuff when dealing with header files. You need to learn about #ifndef/#define/#endif. These three keywords work together to allow a header file to be used multiple times without warnings/errors about multiply definining something.
The general structure we see in a header file using these three keywords is as such. Say we have a simple file called test.h

test.h

#ifndef _TEST_H_
#define _TEST_H_

//All content of the header file would go here,
//between the #define and #endif

#endif

Now, let me explain what each part means. First, the #ifndef stands for "If Not Defined." This is a pretty simple concept to grasp: "If the following has not been defined yet, then define it. If it has, then just skip the defining process. The next line "#define _TEST_H_" is the beginning of the defining sequence. You may give it any name you wish, I chose _TEST_H_ because I know I will never use that name again, hence avoiding defining something twice. I make it usual practice to make the define name the same as the name of the file, in all caps with a _ preceding and following. The next line is #endif, which basically tells the compiler that it's done defining! Any lines of code found within #define and #endif are the actual parts being defined. So, here we have a sort of "multiple line" define. Lets use this on our example from before.

We need to modify the main function a little bit, and create a new file called "ask_question.h"


4b_main.cpp

#include <iostream.h> //Required header file for i/o streams
#include "ask_question.h"

int main() // The main function. This is where the program starts
{
cout << "Hello world!" << endl; // Output a hello statement
ask_question(); // Call the function called ask_question.
return(0);
}

ask_question.cpp

#include <iostream.h> // This header file is required for i/o stream processes

void ask_question(void) // A function to ask a question
{
int age = 0; // Declare an integer called age, which we use to store input
cout << "What is your age:"; // Out put the question phrase
cin >> age; // Input the typed in number into the variable age
cout << "Wow, you're " << age << " years old!" << endl; // Output a nice little message
}

ask_question.h
#ifndef _ASK_QUESTION_H_
#define _ASK_QUESTION_H_

void ask_question(void);

#endif

Okay! So, as you can see, ask_question.cpp remained the same. The main function changed only slightly, as we removed the extern line, and instead added an #include which included the new ask_question.h. So, the only real new thing is ask_question.h. You can see that I've used the three keywords and have my declaration between the #define and #endif. It may be a bit confusing to see the declaration "void ask_question(void);", which is the same exact declaration as in ask_question.cpp. Why doesn't this produce a redefinition error? Well, if we were using this header file to allow access to, say, an integer, and in the header file we simply copied the declaration of that integer -- we would get an error. An extern would be required! Try putting an extern right before the line "void ask_question(void);" in ask_question.h. You will see that it still works! The reason that a function can be declared in a header file without extern and a variable can't isn't of utmost importance right now. Just know that with functions the extern is not required. Think of it as a little "trick."

Back To Contents

5. Classes and header files

Alright, so now we're ready to get into some more-advanced stuff. If you're not comfortable with all the previous knowledge you've gained, please, play around with the code and make lots of examples. Once you've become comfortable with the information and understand how it all works, continue with the article. Also, if you don't know what classes are and how to use them -- go read up in your C++ tutorial somewhere. I will not be explaining their use, but rather how to organize them with header files.

Okay, so what I've taught you so far is quite wonderful and such -- but there is even more power to it. This comes in when dealing with classes! Using classes from one file in another file can be quite tricky. You can't just extern it like a variable, since it requires more information - like what members the class has and things like that. The only way to do it properly and efficiently is using a source/header file combination! Here's how it works.
The source file contains all of the actual processing code. For instance, it will hold all functions. The header file contains the actual definition of the class and it's members and functions - but not the actual function code. The header file serves as the link which allows you to use your class in any other source file.

Let's take a look at a very simple class.

class box
{
public:
   int side_length;
   
   void reduce_side_length(void)
   {
     side_length -= 1;
   }
};

Here is a simple class that has a member variable side_length and a member function reduce_side_length(); I won't deal with constructors and destructors, etc.

Now, how do we split up this simple class between a source file and a header file? First, we need some names. Let's call our files box.cpp and box.h.

Let us first take a look at box.h
#ifndef _BOX_H_
#define _BOX_H_

class box
{
public:
  int side_length;

  void reduce_side_length(void);
};

extern box the_box;

#endif


And here is box.cpp

#include "box.h"

void box::reduce_side_length(void)
{
 side_length -= 1;
}

box the_box;


Lastly, 5_main.cpp
#include <iostream.h> //Required header file for i/o streams
#include "box.h" // Include the box header file

int main() // The main function. This is where the program starts
{
cout << "Hello world!" << endl; // Output a hello statement

the_box.side_length = 10; // Set the side_length to 10

cout << "The box side length is: " << the_box.side_length << "." << endl; // Output the side length

the_box.reduce_side_length(); // Call the member function of the box class

cout << "The box side length reduced is: " << the_box.side_length << "." << endl; // Output the new length

return(0);
}


Okay, so there's some advanced stuff going on here, so let me explain it all as best I can. First let's look at the header file. As you can see, it's pretty much just the delaration of the class within the three defining keywords. The only difference you will notice is that the function is declared in the class, but only the name of the function, nothing else. This lets the header file know that the actual contents of the function is defined somewhere else; in our case box.cpp.

So, lets take a look at box.cpp. First, we need to include the box header file, or else we won't be able to access anything from the box class. Next, we actually define the contents of the function. In order to say that the function belongs to the box class, we need to have the box::. This signifies that the function is a member of box. After that, we declare the function normally as we would with any other function.

Now about those red lines. In order to actually use the class in the example, we need to declare an instance of the class. These red lines show you how to declare the instance of that class in one file, and use the header file to make it accessible to any file you wish to use it in. The actual declaration of the instance of the class is in box.cpp: box the_box. And, using the knowledge we know about header files, we just put an extern line at the end of box.h, before the #endif: extern box the_box.

Okay, so onto main.cpp. This file is actually quite simple. We include the box header file, and then just access the members of the box class just as if it was declared within the main.cpp source file. There's really not much to explain here.

Back To Contents

6. Summing it up
Sadly to say, this is about all I have to offer you! It should be enough to get you on your way with organizing your project. By simply using these methods, you can split up your code into easy-to-find files which will make your programming experience much easier. This is just my own opinion, however. It's up to you to try this style and see if it works. If it doesn't work for you, think about why it doesn't work. Then, go about and fix that problem. Eventually you will find a method that fits you perfectly and allows you to navigate through your code with ease. Good luck!
Back To Contents

7. End Notes

As for an end to this much-too-long article, I would like to state once again that what you have just read are my personal ideas and thoughts own how to organize your project. In no way is this the "correct" way to do so. In fact, it may be the most incorrect way to go about structuring your program and it's files, but for me it works flawlessley and effortlessly. I'm sure many other programmers would agree as well. It's really up to you to decide what you like best, and what works best for you.

I'd like to thank you for taking the time to read my article! It took a while to write, but it was well worth it to get my ideas out there in the open and give some guidance to those who need it.
If you have found something about this article that does not quite suit your fancy, or is confusing you, or some of the example code doesn't work -- feel free to drop a line.

Back To Contents