• Advertisement
Sign in to follow this  

how do I add module?

This topic is 4249 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I know that asking this question must make me look very dumb, but I have never actually done this before... I am working in Visual C++ 2005 Express. My game has a single main .cpp file and a bunch of headers (including enum calls, #defines, and class definitions.) The header files that define classes currently contain the class definitions _and_ the full method descriptions. (like so):
//welcome to SomeClass.h
class SomeClass
{
    void SomeClassMethod();
};

SomeClass::SomeClassMethod()
{
   //whatever
    return;
}

I've seen that people usually put the methods of their classes in separate .cpp files. How do I do that, exactly, and how do I connect the new .cpp files to the project? I obviously can't just say " #include SomeClass.cpp " in my main .cpp file. By the way, is there anything actually wrong with the organization I currently use, or is it just out of vogue? Thanks!

Share this post


Link to post
Share on other sites
Advertisement
Normally you put definitions in your header file of the class and the descriptions in your cpp file.

Example:


//Class.h
//Here you can put another headers that you need
class Test
{
.
.
.
}

//Class.cpp
//Here you can put also another headers that you need
#include "Class.h"

Test::Test()
{
}

.
.
.





Thats that simple

Share this post


Link to post
Share on other sites
Quote:
Original post by synth_cat
I know that asking this question must make me look very dumb, but I have never actually done this before...


Then why not post in For Beginners?

Quote:

I've seen that people usually put the methods of their classes in separate .cpp files.


Yes; you *must* either do this, or cause the function to be marked inline (either by putting it inline in the class definition, or by marking it with the 'inline' keyword). Or put the class definition into the .cpp instead; but that *only* works if *no* other "modules" need to "see" the class definition (if they don't/shouldn't, then by all means do this! As a general rule, put as absolute-little in your header files as you can get away with. Narrow the interface.

Quote:
How do I do that, exactly, and how do I connect the new .cpp files to the project? I obviously can't just say " #include SomeClass.cpp " in my main .cpp file.


From the .cpp, as well as any other source file that makes use of the class definitions, include the .h. Tell the compiler to compile the .cpp, and to link the resulting object file (.o, .obj etc.) when creating the executable. The details of how to do that depend on your compiler and/or IDE (if any).

Quote:
By the way, is there anything actually wrong with the organization I currently use, or is it just out of vogue?


See above. If more than one other module needs to use SomeClass, you WILL get "multiple symbol definition" linker errors (assuming you succesfully informed the compiler/IDE that SomeClass is in the project), EVEN IF you have proper include guards on your header file (which you should put anyway).

Share this post


Link to post
Share on other sites
If you have a project in Visual C++, linking your .cpp files into the program is trivially easy. Just select "Project"->"Add New Item..." in the menu, and select "C++ File (.cpp)" in the list. Then you can just type up your implementation of the class (don't forget to #include the header file!).

When you hit "Build", Visual C++ will automatically link in all the C++ files that are included in your project.

Of course, it's also a good idea to learn how to put together and link a project the old-fashioned way (i.e., using command-line tools and makefiles), but if you're using Visual Studio, this is the easy way to do it. [smile]

Share this post


Link to post
Share on other sites
So when I have created "MyClass.cpp" and added an #include "myclass.h" to it, do I still have to add a #include "myclass." to my main .cpp file?

Quote:

If more than one other module needs to use SomeClass, you WILL get "multiple symbol definition" linker errors (assuming you succesfully informed the compiler/IDE that SomeClass is in the project), EVEN IF you have proper include guards on your header file (which you should put anyway).

I don't really understand what situation this is describing. Could you give me an example? And what are the "include guards" for a header file, anyway? I thought include guards were used to restrict #include-ing a header file more than once (which seems to be somewhat out of context, unless there's something else I'm missing.)

Share this post


Link to post
Share on other sites
All the .cpp files in your project will get compiled and linked together automatically by the editor, so don't worry about that. Just make sure you have the proper headers included in all the cpp files

Also, make sure to use inclusion guards in all your headers. #pragma once a t the top of all headers will do the trick, it will stop you from getting multiple inclusion errors.

Share this post


Link to post
Share on other sites
in VS2005, once you have a project started, these three are your friend:

Project->Add Class...
Project->Add New Item...
Project->Add Existing Item...

You may or may not have noticed that there is a file with a vcproj extension. This is your project file. It is actually an XML file, and contains all of the files in your project, including which ones to compile.

Basically, if your cpp file shows up in the project explorer, it'll be compiled.

Headers don't have to show up in the project explorer, but it is useful to have them there for easy browsing.

Share this post


Link to post
Share on other sites
So let me just see if I've understood this:

I create a .cpp file by way of Project->Add Item that contains the implementation of my class's methods, and call it "myclass.cpp" Then I add the line "#pragma one" to the tops of all my .h files. Then I add "#include myclass.h" to both "main_file.cpp" _and_ "myclass.cpp."

Does that sound about right?

Share this post


Link to post
Share on other sites
Alright, I did what you guys told me to do. I added new .cpp files to hold the function definitions for my three main classes. I also added the line "#pragma once" to the top of all my class definition header files.

It didn't exactly work: the program would not build and I got sent about 400 errors. The problem is that now the new .cpp files need certain #includes to be valid, but it doesn't work properly because the new .cpp files are compiled _before_ my main .cpp file.

Let me simplify all this and create a hypothetical situation so that I can ask my questions effectively (I am very sorry if this gets a bit long - it's hard to state this briefly):

1) I have two classes in my program: MyClassA and MyClassB

2) I have two .h files: one for each class. Note that at this point the methods are defined within the .h files!

Here is "myclassa.h"

class MyClassA
{
public:
void MethodA();
};

void MyClassA::MethodA()
{
//whatever
}




Here is "myclassb.h"

class MyClassB
{
public:
//note the line below!
MyClassA* mclassa_pnt;

void MethodB();
};

void MyClassB::MethodB()
{
//whatever
}




3) Both classes require information defined in another header file called (for simplicity) "generaldefines.h" This file contains macros, structs, enums, or whatever. Also, both classes contain things like D3DXVECTOR3 (in other words, d3d9.h and d3d9x.h need to be included before the compiler looks through myclassa.h and myclassb.h. Let's also say, for laughs, that the myclassa.h and myclassb.h perform std::string operations, so #include <string> must occur before they are looked at.

4) MyClassB contains a MyClassA pointer (see above files.) Thus, MyClassA _must_ be defined before the compiler even looks at myclassa.h

So the top of my main .cpp file looks something like this:

#include <windows.h>
#include <d3d9.h>
#include <d3dx9.h>
#include <string>

#include "generaldefines.h"

#include "myclassa.h"
#include "myclassb.h"

using namespace std;

//main loop, etc....




As you can see, this all works OK because myclassa.h and myclassb.h are included _after_ the compiler has gone through d3d9.h, d3dx9.h, string, and generaldefines.h. Also, there is no problem created by MyClassB requiring a pointer to MyClassA because #include "myclassa.h" is called before "myclassb.h"

Then, however, you guys told me that this structure was wrong, that my class methods should be defined in their own .cpp files. So I added myclassa.cpp and myclassb.cpp. I added #include "myclassa.h" to the top of myclassa.cpp, and #include "myclassb.h" to the top of myclassb.cpp. Now that the two header files were getting included twice (in the main .cpp and in either myclassa.cpp or myclassb.cpp), I added the line "#pragma once" to the top of myclassa.h and myclassb.h.

When I tried to run this whole thing, all heck broke loose. The problem was obvious: myclassa.cpp and myclassb.cpp were compiled before my main .cpp file. Thus, the info from d3d9.h, d3dx9.h, generaldefines.h, and string was not yet defined when the compiler started to read through myclassa.cpp and myclassb.cpp.

So here's my question: Is it OK to add this to the top of my myclassa.cpp file?

//I'm not sure if I'm doing this #ifdef check correctly, but I figured it must be necessary since I don't know if the file d3d9.h has the line #pragma once at the top of it
#ifndef d3d9.h
#include <d3d9.h>
#endif

#ifndef d3dx9.h
#include <d3dx9.h>
#endif

#ifndef string
#include <string>
#endif

#include "generaldefines.h"

#include "synthgame.h"



and do the same thing for myclassb.cpp, including a the line "#include myclassa.h" so that MyClassB's MyClassA* value would be valid within myclassb.h?

This is what I have currently done, and my program does build with no errors, but I'm uncomfortable with this and want someone's approval. Did I do this right? Is it OK to call all those defines in multiple .cpp files? Did I do my "#ifndef" check correctly? Will I have to use it every single time I #include d3d9.h or string, since now I have multiple .cpp files and I'm never sure which order they will compile in?

Any help would be greatly appreciated! (I'm sorry I was so long-winded here.)

Share this post


Link to post
Share on other sites
Dave Hunt - Yes, that is a good article. I just read it, actually. However, it doesn't answer a few questions.

Do I need to write my own #include guards for d3d9.h, d3d9x.h and string (since all my source files will need these #includes)? When I say "write my own #include guards", I mean doing this:

//inside sourcefile.cpp
#ifndef d3d9.h
#include d3d9.h
#endif


If so, what do look like (I'm sure I didn't do it correctly)? I don't need to worry about this for my own header files, since I can just say "#pragma once" at the top of them, but I am unsure about the ones that I do not write.

Are there any special rules about calling the line "#include <string>" multiple times (across different source files)? I was just curious, seeing as the line says <string> and not <string.h>

Share this post


Link to post
Share on other sites
Quote:
Original post by synth_cat
Do I need to write my own #include guards for d3d9.h, d3d9x.h and string (since all my source files will need these #includes)? When I say "write my own #include guards", I mean doing this:
*** Source Snippet Removed ***


No. Include guards go in headers. The headers for libraries you include already do this, because the people who wrote the libraries are not idiots. :)

If so, what do look like (I'm sure I didn't do it correctly)? I don't need to worry about this for my own header files, since I can just say "#pragma once" at the top of them, but I am unsure about the ones that I do not write.[/quote]

They look basically like that, except you'll want to use underscores instead of periods. Actually, any 'symbol' the preprocessor can understand is fine, as long as the #ifndef and #define use the same one, and it's not already in use for something else.

DO NOT put a leading underscore and then a capital letter, or put two or more leading underscores. Those symbol names are reserved.

DO NOT rely on #pragma once. You can put it in in addition to an include guard, but it will only replace the include guard functionality for compilers that respect it. All #pragmas are compiler-specific.

DO use all caps. It's expected to use all caps for most things that involve the preprocessor, so that they really stand out.

DO base the symbol name off of the file name; that avoids collisions between your own names.

Are there any special rules about calling the line "#include <string>" multiple times (across different source files)? I was just curious, seeing as the line says <string> and not <string.h>[/quote]

No. There is nothing special about that header, and a properly guarded header, which is properly constructed (as the standard library headers are), can be included any number of times. The reason it says "string" and not "string.h" is that *these are different headers*. "string" provides the C++ standard library std::string class. "string.h" provides, to C programs, the C standard library functions for manipulating char*'s: i.e. strlen(), strcat() etc. C++ programs should not use these if possible; if they are needed, you should include "cstring" instead, which will put those functions into the std namespace.




Anyway. The 400 errors you're getting (assuming the code compiles OK and is just not linking) are exactly because of just what I was telling you about: you provided an exact example of the "whole situation I was describing" that you didn't get:

Quote:

If more than one other module needs to use SomeClass, you WILL get "multiple symbol definition" linker errors (assuming you succesfully informed the compiler/IDE that SomeClass is in the project), EVEN IF you have proper include guards on your header file (which you should put anyway).


At its most basic: compiling and linking are separate steps. Include guards protect *compilation*, by restricting the included source that the compiler sees. (Without the guards, the headers get pasted in multiple times, and the compiler sees multiple declarations of things.)

Proper header design - interface (declaration) in header, implementation (definiton) in implementation file - protects *linking*, by making sure the implementations only exist in one object file.

Every .cpp file you have, roughly speaking, gets translated into an object file. Including the headers - assuming they are properly done - includes the *declarations*, which is *only* so that the compiler knows what the various symbols mean (e.g. if you do "foo(bar)", it needs to know if 'foo' is a free function, an instance of a class that overloads operator(), or something else that might or might not imply that there are syntax errors). But every source file that includes a header includes everything that's in the header. If, therefore, the header provides an *implementation* (definition), then every source file that includes the header will get compiled into an object file that includes the implementation. Object files don't 'store' declarations; rather, they only provide special names for each implemented thingy so that the linker can mix and match them into a single executable.

After everything is compiled into an object file, the linker attempts to link the object files. That is, for each thingy in each object file that refers to some other thingies, it looks for the other thingies in all the object files that are being linked together.

If it doesn't find the called-upon thingy, you get a linker error (unresolved reference), because there's nothing that can be put in place.

If it finds *exactly one* implementation, then it manipulates the "hanging" reference so that it now calls upon that implementation directly.

If it finds *more than one* implementation, *even if they are identical* (as they would be if they got "cloned" by a bad header), you get a linker error (multiply defined reference), because the linker doesn't know which one to use: there are no rules defined that would make one preferable to another.

So when you need to declare a global variable in your header, you write an 'extern' declaration. This way, you ONLY declare the variable (rather than defining it): you tell the compiler "'foo' is an int, ok? It will be defined somewhere, so let the linker worry about that part. You just do the magic for creating references to ints when you see 'foo'."

Then, in ONE source file, you put the actual global variable.

Similarly, when you define a function, including members of a class, you put the declaration in the header, and the definition in the corresponding source file. Functions are also "thingies" for the purpose of this discussion.




Inline functions (this includes functions explicitly marked 'inline', functions defined *inside the class definition*, and all manner of template stuff) are an exception: they go into the header, because they work with a different linkage model. The idea is that the compiler is going to try really hard not to generate actual symbols for these things, but instead insert the function code (or whatever) directly at all of the call sites, rather than having an actual function call to an actual function. If for some reason it can't do this, then it will still create the impression (from the linker's perspective) that it did. No actual function -> no symbol -> no multiple symbol definition errors. Meanwhile, template stuff actually often *needs* to go into the header, for really nasty technical reasons.

You SHOULD NOT just mindlessly mark things inline to take advantage of this, though, because (a) its use is limited anyway - functions only - and (b) you probably don't want that inlining behaviour happening all over the place: it can seriously bloat your executable. Also, it evades the one *useful* property of the (retarded) C/C++ linking model: it provides a convenient way to publish interfaces and hide implementations. Normally, interfaces are much more stable than implementations. Keeping the header to just an interface means it will need to be recompiled less often, and whenever you recompile a header, you have to recompile *everything that includes it* - of course, the makefile will keep track of these "dependancies", but it's still a big ouch in terms of project maintenance.

Share this post


Link to post
Share on other sites
Well, thanks a lot, Zahlman! That really clears things up for me. I've got the program working now, as modulated as it ever will be.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement