Sign in to follow this  
Chrono1081

Still confused about header and cpp files :(

Recommended Posts

After trying many times to separate files and having nothing work correctly I learned that some online tutorials and some books I have are incorrect and am looking for clarification. I've seen many times in many places written that "To the compiler there is no difference between .h and .cpp files" well, after literally a few weeks of trying to figure out why my code wont compile I learned they ARE different but I don't understand what the difference really is. I had an SDL framework I was making and after a few weeks of re-writing and getting frustrated on a whim I moved all my header files to CPP files and about fainted when everything compiled perfectly. Can anyone explain to me the difference between these two files? My assumption is that the compiler is looking for something that its not seeing because if I have a class, the .h and .cpp files work fine, but if I have a function that is fairly large and I want it in its own file it HAS to be in a CPP file. I can add a .h file but it doesn't do anything accept contain the preprocessor directives and add space. EDIT: Yes I've already read the gamedev article on this many times :)

Share this post


Link to post
Share on other sites
EDIT: Sorry for the mess, I didn't know [code ] tags didn't work here. :(

Okay, so you know how you can declare a function right after your #include statements and define it as well?

i.e.

#include <iostream>

using namespace std;

void printHello()
{
cout << "Hello" << endl;
}


Well, you can also just declare the function there and then define it after your main function, i.e.

#include <iostream>

using namespace std;

void printHello();

int main()
{
blah blah
return 0;
}

void printHellow
{
cout << "Hello" << endl;
}


This is so that you can just look near the top of your file and see what kinds of functions you have, what arguments they take, and what they spit out. This is useful if you're working on something in the middle of your main() function or something and suddenly forget the details of some function you wrote. Instead of trying to find that function by wading through all of the definitions, you just have them all neatly listed up top. If you need more info, then you can start wading through the other definitions.

Well, the way I was taught is that .h and .cpp files work the same way. You can just make one .h file and both declare and define your functions right there from the start, OR you can simply *declare* your functions in your .h file and then define them in the .cpp file.

The reason you'd want to do this is because you might want other people to use your files. Say you are making a game with a friend and he wants to implement some graphics, but you did the majority of the work for that. Instead of reading through a wall of text where it's hard to tell how many functions there are and what they do, etc., he can just look at the .h file and see things like "void render();" or whatever. Then if he wants to know how that function works, he can go to the .cpp file where that is explained.

The way you make a .cpp/.h file is you make your .h file first.


//functions.h

#include <all your junk>

using namespace std;

void function1(int,float);
int function2();
etc.


And then in your .cpp file you'd have something like this:


#include <all your junk>
#include "functions.h"

using namespace std;

void function1(int foo, float bar)
{
blah;
}

etc.

Share this post


Link to post
Share on other sites
It is very important to break up code into files since it is easier to code and debug fifty/hundred lines of code rather than a shooting-match of thousands of un-commented lines.

The convention I use ( and others ) is to put each class in its own file. I just, a couple of minutes ago, have written a bare-bones class that I will be using. I will post it here to show you how one can break up classes into files and how to use these files. I am writing a sim/strategy game and there will be plant life in the game world, so I need a class to manage the life cycle of the plants. The class is called: PlantManager.

Here it is:

The header file: plantManager.h

#ifndef PLANTMANAGER_H_INCLUDED
#define PLANTMANAGER_H_INCLUDED

class PlantManager
{
private:


public:

PlantManager(); // default-no argument constructor.

~PlantManager(); // destructor
};

#endif // PLANTMANAGER_H_INCLUDED




and its corresponding .cpp source file: plantManager.cpp


#include "plantManager.h"



PlantManager::PlantManager()
{
}

PlantManager::~PlantManager()
{
}




Now we can see that it has no methods, but they can be added by me in a little bit. The header file has the #ifndef and the #define line at the beginning and the #endif line at the end. These are called inclusion guards. These guards basically prevent redefinition of classes, for example, which causes compilation errors.

You can then fill in private members and add more public methods to the class. Once complete this class can be used in another class or the main program:


/* example: using the plantManager class */
#include "plantManager.h"

int main ()
{

PlantManager plantMgr; // we now have a PlantManager object!

return 0;
}

Share this post


Link to post
Share on other sites
The .h files works like a table of content for the .cpp files. The header files are good for people who are looking at the source code, so they can see what functions exist in the class. The seperation is for better understanding of the source. Also, you include .h files instead of .cpp files to avoid bloating.

Share this post


Link to post
Share on other sites
Let's say we are writing a program called Foo. We are going to have two source files, a.cpp, and b.cpp, and write some code in one and the rest in the other. Just as an example. Forget about what exactly this code is for a moment. There's a fundamental point about the compilation process.

Create a program can roughly be divided into two stages. Compiling and linking. Compiling works on individual source files. Let's say you are compiling a.cpp. You might say, what about b.cpp. It doesn't matter. Compiling always applies to individual source files. There is no concept of a complete program. There is also no concept of other files. It's just one file. So you compile a.cpp, and compile b.cpp, independently. (The result is some intermediate file we call an object file.) In the second stage, we link. Linking is the process of taking many many object files, and putting them all together into some kind of end result. Like an executable. Compiling: source files independently. Linking: put everything together.

Back to our example. Let's create a function called addTwo. It looks like
int addTwo(int a, int b) { return a + b }
And let's put this function, in say, a.cpp. We have just defined the function addTwo. Can we compile a.cpp? Sure. It's valid code. Forget about linking to some end result. We can compile a.cpp.

Now, we want to create a function called addFour. And we might say to ourselves, ahh, we have a function called addTwo that we can use. So we may have:
int addFour(int a, int b, int c, int d) { return addTwo(addTwo(a,b), addTwo(c,d)) }
Let's put this code in b.cpp. Now, can we compile b.cpp? Remember, source files are compiled independently. So looking at addFour, we use this function called addTwo. And looking for addTwo, oh, it doesn't exist. There's no mention of it. You'll get a compile error.

So we need a way to indicate that addTwo exists elsewhere. This is where a declaration comes in. If we put, at the top of b.cpp,
int addTwo(int, int)
we have declared the relevant function. There's no code for it, because the code is already in a.cpp. We just want to indicate its existence.

This is a nice compact example. But what happens when we scale it up? Instead of addTwo, let's have addTwo, addThree, addFour, etc. all the way up to addNine in a.cpp. Furthermore, we don't just have b.cpp that needs to use the functions in a.cpp. We have c.cpp, d.cpp, etc. all the way to z.cpp. Now, do you want to be repeatedly typing in the declarations for all those 25 files? It would be so convenient if we could just put the declarations into one file. And then somehow have this file copy pasted as needed.

Like a header file and the #include directive. A header file contains these declarations. What you're simply doing is putting in things that need to go into multiple source files like declarations, all in one header file. Then copy paste with #include.

Share this post


Link to post
Share on other sites
Quote:
Original post by Chrono1081
if I have a class, the .h and .cpp files work fine, but if I have a function that is fairly large and I want it in its own file it HAS to be in a CPP file.[...]
EDIT: Yes I've already read the gamedev article on this many times :)

If the second point is true, why do you seem surprised at the first point?

I think most of this is clear in the article (I wrote it) but obviously not everybody understands what I was trying to say with it. The idea is to split your code across .cpp files, and then add .h files to describe the content of the .cpp files. In the article there is a list of things to put in header files; you can assume that if something isn't on that list (eg. a function body) then it shouldn't be in a header.

Share this post


Link to post
Share on other sites
Quote:
Original post by Chrono1081
I've seen many times in many places written that "To the compiler there is no difference between .h and .cpp files"


There isn't a difference between .h and .cpp files, to the compiler. There is a difference between header files and implementation files, to the programmer. But the extensions ".h" and ".cpp" are not (especially) magical. (Some compilers will draw a distinction between ".c" and ".cpp" files to decide whether you are trying to write C code or C++ code, but they'll let you override that, too.)

Quote:
but I don't understand what the difference really is.


Implementation files contain implementation. Header files contain interfaces.

The implementation of a variable is its definition. The interface to a variable (if needed) is a declaration.

The implementation of a function is its definition, which consists of a signature (the return type, name of the function and parameter list) and a body (the actual code for the function). The interface is a declaration, which consists of just a signature and a semicolon.

The words "definition" and "declaration" are perfectly normal English words, by the way, and you should look them up if you don't already think of them that way.

Because of how these things are constructed, definitions serve as declarations as well. However, because everything has to be declared before its first use, and because we can only have one defintion of each thing, we sometimes need separate declarations.

When you write a header file, you are making declarations for things that are defined in the corresponding implementation file. This allows every implementation file that #includes that header to know about those things, because they are now declared. The #include is a literal copy-and-paste job; the preprocessor takes the header's text and sticks it in place in each implementation file that #includes the header. That's why we put #include statements at the top of the file: to make sure that the declarations appear before the uses, in the processed result (called a translation unit).

Now that the declarations are in place, the compiler can understand the uses. In the implementation file, we write the corresponding definition. Because the header will be included in other implementation files (forming other translation units), we end up with declarations in some translation units that refer to a definition in a different translation unit. Because of this, the declaration needs to be 'extern'. This works automatically for functions and classes, but for global variables, we need to add the 'extern' keyword to the declaration.

Remember, we can only have one definition of each thing. Therefore, implementation has to be kept out of the header files (with two notable exceptions: template code - because it isn't actually defined within the template, but only when the template is instantiated - and things which are marked 'inline', which is also implicit for stuff written inside a class body). Otherwise, you get a "multiply defined symbol" (or something similar) error from the linker. You also need to have an implementation somewhere for everything that's used, or you get an "undefined symbol" (or similar) linker error. This is especially tricky with static class members: a line inside a class body describing a static member is only a declaration, not a definition. (The non-static members are also only declarations, but that doesn't matter because the class only defines a data type, which you instantiate later.)

Quote:
if I have a class, the .h and .cpp files work fine


A class only defines a data type. As such, the class body is a declaration, although you can embed definitions for member functions within it (because they are automatically considered 'inline' by the compiler).

Quote:
but if I have a function that is fairly large and I want it in its own file it HAS to be in a CPP file.


It doesn't matter about the size; the implemenation has to be in an implementation file. If there's more than one copy of it, then you have more than one definition of the same "thing" (the function with that signature), and the linker complains (because it has no way to decide which one to use when someone calls the function). When a file is #included, it copies the file. And the point of putting things into headers is to #include them freely (to produce declarations where they are needed).

Quote:
I can add a .h file but it doesn't do anything accept contain the preprocessor directives and add space.


It should also include a declaration of the function. Actually, try to use a single header for related functions; you don't actually have to put all the implementations in the same implementation file. Implementation files include headers; not the other way around.

So how does the compiler find all your implementations, you ask? Very simple: you have to tell it when you run the compiler. An IDE usually takes care of this for you by creating a "project". On the command line, you just specify all of the .cpp files that are needed, and the compiler creates the translation unit for each one, compiles each translation unit into an object file, and links the object files to make the executable. (Assuming there are no compile or link errors, of course.)

Share this post


Link to post
Share on other sites
Thank you guys for all the replies! Its much clearer now :)

I understood the concept behind it I just couldn't get it to work correctly. Now so far *knock on wood* everything I've split up has worked just fine. Thank you guys again :)

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this