🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

C++ Workshop - OO Analysis, Design, & Porgramming (Ch. 6 & Ch. 11)

Started by
75 comments, last by Dbproguy 16 years, 2 months ago
main.cpp should include soldier.hpp, not soldier.cpp. Cpp files almost never include other cpp files.

Why this actually caused problems -

The extension 'cpp' is only meaningful to your IDE. Your compiler doesn't care - it is told to compile some file. It's name, and extension, could be anything. The '.cpp' and '.hpp/.h' extensions are a naming convention used to differentiate files that should be compiled and those that are just for including in others. When you click 'build' in DevCPP, it goes through all the files in your project and invokes the compiler for any with the extension '.cpp'.

What happened in your case was that DevCPP compiled soldier.cpp, creating soldier.obj - which contained all the code in soldier.cpp. Then it compiled main.cpp, into main.obj. Since main.cpp included soldier.cpp, main.obj also contained all the code in soldier.cpp. (Or vice versa; it could compile main.cpp first, and probably does - alphabetical ordering in your project's file list)

Now, DevCPP invokes the linker on soldier.obj and main.obj. The linker discoveres that all that stuff in soldier.cpp is in both obj files; and it spits out an 'multiple definition of X' error.

(P.S., linker errors don't give you line numbers because the linker isn't working with your source code anymore - it's working with the output of the compiler; a seperate program; and all that line information is gone. (Except in debug builds (And it doesn't do any good then because linker errors rarely represent problems local to a single line, the way a syntax error would) ) )
Advertisement
Your second error (undefined reference to Soldier::Soldier()) is probably because you forgot to actually define Soldier's constructor. In your header, you might have 'Soldier::Soldier();', but then you never have 'Soldier::Soldier() { /* code */ }' anywhere. You need to give the constructor a body too - it might have a funny signature, but it's still just a function.
Deyja:

So in big real projects, there is ONE file which contains all class' and functions' implementations, plus the main() implementation? in one single file? and that file (main.cpp) just includes the headers from some header.hpp? that makes for one heck of a enormous file...I would have imagined that all the above mentionned should be seperated into multiple different files, and just include them all together.
Quote: Original post by kingIZZZY
Deyja:

So in big real projects, there is ONE file which contains all class' and functions' implementations, plus the main() implementation? in one single file? and that file (main.cpp) just includes the headers from some header.hpp? that makes for one heck of a enormous file...I would have imagined that all the above mentionned should be seperated into multiple different files, and just include them all together.

No, the implementations are separated in their own files. For example:

Soldier.hpp
#ifndef SOLDIER_HPP#define SOLDIER_HPPclass Soldier {  public:    Soldier();    void DoSomthing();};#endif

Soldier.cpp
#include "Soldier.hpp"Soldier::Soldier() {  // Construct soldier}void Soldier::DoSomething() {  // Do something with soldier.}

main.cpp
#include "Soldier.hpp"int main() {  Soldier soldier;  // Use soldier}


It's the job of the linker to then combine the compiled object code from both main.cpp and Soldier.cpp into a single executable. This is usually hidden from you when you use an IDE, which implicitly links together every implementation file that is in your project.


jfl.
Wow, thanx for the fast response. This bit of info wasnt so clear from deyja.
Most books don't use an IDE, so they have you just include your cpp files into the main one. That's simplest for the beginner; he needn't worry about some long make file - he's only got one object file to build anyway. Obviously, it falls apart when you use an IDE that does all that make file jazz for you.
hmm, i tried again, this time like jflanglois demonstrated, (i did not include Soldier.cpp (which holds the implementation to the class) into anything), i just included ClassSoldier.hpp (which holds the class' declaration) into main.cpp.

The compiler complains that "soldier has not been declared";

4 C:\Dev-Cpp\MyProjects(userAdded)\Learning\copyConsturctor\Soldier.cpp `Soldier' has not been declared

Maybe the implementation gets compiled before main.cpp, how could this be resolved? how is it done in real big projects?
Quote: Original post by kingIZZZY
hmm, i tried again, this time like jflanglois demonstrated, (i did not include Soldier.cpp (which holds the implementation to the class) into anything), i just included ClassSoldier.hpp (which holds the class' declaration) into main.cpp.

The compiler complains that "soldier has not been declared";

4 C:\Dev-Cpp\MyProjects(userAdded)\Learning\copyConsturctor\Soldier.cpp `Soldier' has not been declared

Maybe the implementation gets compiled before main.cpp, how could this be resolved? how is it done in real big projects?

Make sure that you #include "ClassSoldier.hpp" in Soldier.cpp, otherwise it does not know what Soldier is. My example had #include "Soldier.hpp".
oh ok,
but does this mean i need to include all the declaration-headers into all of their respective implementation files, aswell as include all headers into main?

//firstOfaMillionDeclaration.hpp
class firstOfaMillionClasses{// class declaration// there are another 999,999 declarations out there}



//firstOfaMillionImplementation.cpp
#include "firstOfaMillionDeclaration.hpp"// implementation of first out of a million classes



//main.cpp
#include "firstOfaMillionDeclaration.hpp"#include "secondOfaMillionDeclaration.hpp"#include ...


when i do this (i.e. include the declaration file header into both main and the implementation file), i get a linker error:

[Linker error] undefined reference to `Soldier::Soldier()'
Quote: Original post by kingIZZZY
oh ok,
but does this mean i need to include all the declaration-headers into all of their respective implementation files, aswell as include all headers into main?

No, you need to include only what is necessary for that compilation unit. So if main.cpp uses Soldier, include the Soldier header. After that, how you divide your code is up to you. If you want to implement multiple classes in one implementation file, you are free to do so, although generally, the less compilation units, the lower the benefits. Read this article for almost everything you need to know about dividing your code into multiple files.

Quote: when i do this (i.e. include the declaration file header into both main and the implementation file), i get a linker error:

[Linker error] undefined reference to `Soldier::Soldier()'

Chances are that your implementation file (firstOfaMillionImplementation.cpp) is not a part of your project. To fix this, you need to create a project in Dev-C++:

- Go to File->New->Project...
- Choose Empty Project
- Give your project a name
- Click OK
- Select a location to save the project file
- Go to Project->Add to Project
- Select all your source files
- Compile

To understand why you were getting a linker error, you need to understand that without a project, you are only compiling and linking the source file that you are editting (in this case, main.cpp). If you selected firstOfaMillionImplementation.cpp and hit compile, you would get a different linker error, this time having to do with main() missing. You also need to understand what #include does. #include essentially copies everything that appears in the header file into the implementation file at the place where the #include directive is. For example:

Test.hpp
class Test {
  public:
    void DoSomething();
};

Test.cpp
#include "Test.hpp"

void Test::DoSomething() {
}

main.cpp
#include "Test.hpp"

int main() {
  Test t;
  t.DoSomething();
}


When the pre-processor runs, it yeilds two files, which are the result of Function.cpp and main.cpp, let's call them Test.pre and main.pre:

Test.pre
class Test {
  public:
    void DoSomething();
};

void Test::DoSomething() {
}

main.pre
class Test {
  public:
    void DoSomething();
};

int main() {
  Test t;
  t.DoSomething();
}

Now, the compiler is going to go through each of these pre-processed files and compile them to object code. It does not need to know what DoSomething() does to call it, it just needs to know that it exists and what it is. At this point, you have two object files, let's call them Test.obj and main.obj.
- Test.obj contains the machine code that is the implementation of Test::DoSomething, but it does not contain the code for main(), which is required by a console C++ program.
- main.obj contains the machine code for main(), and it references a class called Test and one of its functions, DoSomething(), but it does not contain the actual machine code of DoSomthing(), it just knows that it exists, somewhere (you were trying to run this, when you did not have a project).
Now, the linker is going to link these two object files together, bringing all the required information into a single executable.

I hope this is not more confusing than anything.


jfl.

This topic is closed to new replies.

Advertisement