Skip to main content
GameDev.net gamedev.net
🔒 Locked

Me vs. Multiple Files : Round 2

Started by NUCLEAR RABBIT Aug 27, 2006 at 12:24 AM 10 replies 2.3k views
Original Post
NUCLEAR RABBIT
NUCLEAR RABBIT
Hello! I recently made a thread about making multiple files, but this thread has a totally different question, so I made him his own home. [lol] Question: I made a project, and split it up into 4 different files, 2 .cpp files and 2 header files. So for my question, In main(), i never include the pet.cpp file, but it knows the function definitions. How does this work, and why? main.cpp

#include "pet_class.h"
#include "Library.h"

void Wait()
{
	std::cout << "\n\nPress ENTER to continue.";
	std::cin.ignore();
	std::cin.get();
}

int main()
{
	Pet pet(10,10,10);

	int menu;
	bool quit = false;

	do 
	{
		system("cls");
		std::cout << "Welcome to the Pet Caretaking Center!\n"
			<< "Programmed by: Brandon Wall\n\n"
				  << "1 = Listen to your pet\n"
				  << "2 = Feed your pet\n"
				  << "3 = Play with your pet\n"
				  << "4 = See Pet's Stats\n"
				  << "5 = quit\n\n"
				  << "Selection: ";
		std::cin >> menu;

		switch (menu)
		{
		case 1:
			pet.Talk();
			break;
		case 2:
			pet.Feed();
			break;
		case 3:
			pet.Play();
			break;
		case 4:
			pet.Stats();
			break;
		case 5:
			quit = true;
			break;
		default:
			std::cout << "\nSorry, " << menu << " is an invalid option.";
			Wait();
		}
	}while(!quit);

	return 0;
}
pet_class.h

#include "Library.h"

class Pet
{
public:
	Pet(int hunger, int lazy, int boredom): m_hunger(hunger), m_boredom(boredom), m_lazy(lazy)
	{}
	void Talk(const int bored = 3);
	void Feed(const int food = 4);
	void Play(const int activity = 4);
	void Stats();
	void CheckStats();
	std::string SetMood();
private:
	int m_hunger;
	int m_boredom;
	int m_lazy;
	int m_mood;
	void PassTime(const int time = 2);
};
pet.cpp

#include "Library.h"
#include "pet_class.h"

//////////////////////////////////////////////////////////////////////////////////////
//
//    GLOBAL FUNCTION DEFINITION
//
//////////////////////////////////////////////////////////////////////////////////////

void Pause()
{
	std::cout << "\n\nPress ENTER to continue.";
	std::cin.ignore();
	std::cin.get();
}

//////////////////////////////////////////////////////////////////////////////////////
//
//    CLASS PET FUNCTION DEFINITIONS
//
//////////////////////////////////////////////////////////////////////////////////////

std::string Pet::SetMood()
{
	m_mood = (m_boredom + m_lazy + m_hunger);

	std::string mood;

	if(m_mood >= 15)
		mood = "Happy";
	else if(m_mood >= 10)
		mood = "Fine";
	else if(m_mood >= 5)
		mood = "Sad";
	else if(m_mood < 5) 
		mood = "Angry";
	else
	{
		m_mood = 0;
		mood = "Sad and Angry";
	}

	return mood;
}

void Pet::CheckStats()
{

	if(m_hunger < 0)
		m_hunger = 0;
	if(m_boredom < 0)
		m_boredom = 0;
	if(m_lazy < 0)
		m_lazy = 0;

}

void Pet::PassTime(const int time)
{
	m_hunger -= time;
	m_boredom -= time;
	m_lazy -= time;
}

void Pet::Talk(const int bored)
{
	std::vector<std::string> phrase;
	phrase.push_back("Pet: Bark Bark Baaaark!!!");
	phrase.push_back("Pet: Arrrrrrr!!!");
	phrase.push_back("Pet: Raaaaawwr!!!!");
	phrase.push_back("Pet: Ahhhhwwwww!!!");

	// Gets random phrase for pet to say to the user
	random_shuffle(phrase.begin(), phrase.end());

	std::cout << "\n" << phrase[0];

	m_boredom += bored;

	PassTime();
	Pause();
}

void Pet::Feed(const int food)
{
	std::cout << "\nPet: Buuuuuurp!!!";

	m_hunger += food;

	PassTime();
	Pause();
}

void Pet::Play(const int activity)
{
	std::cout << "\nPet: Weeeeeeeeee! Bark! :)";

	m_lazy += activity;

	PassTime();
	Pause();
}

void Pet::Stats()
{
	system("cls");

	CheckStats();

	std::string current_mood = SetMood();

	std::cout << "Pat Caretaker Stats:\n"
			  << "\nHunger Level = " << m_hunger
			  << "\nPlayful Level = " << m_lazy
			  << "\nBoredom Level = " << m_boredom
			  << "\n\nOverall Mood: " << current_mood
			  << "\n\nHint: The Higher the Level, the Happy your Pet is.";
	Pause();
}
Library.h

#include <iostream>
#include <string>
#include <algorithm>
#include <vector>

NUCLEAR RABBIT
NUCLEAR RABBIT
Quote:
Original post by Sol462
Because the functions are defined in pet_class.h, which you've included in your main file.


i thought you have to add the cpp file that has to definitions of the functions for them to work. Im kinda confused... [sad]
glBender
glBender
The compiler will get the information it needs from the .cpp automatically
dominicoder
dominicoder
Quote:
Original post by NUCLEAR RABBIT
I made a project, and split it up into 4 different files, 2 .cpp files and 2 header files. So for my question, In main(), i never include the pet.cpp file, but it knows the function definitions. How does this work, and why?


Building a C++ project is a two step process.

First all your source files are compiled, which basically breaks down to syntax checking. If your code is syntactically correct, the compiler will generate object files with the definitions from the functions you defined in your cpp files.

In the second step the linker runs through these object files and finds the appropriate implementation for each function you've declared in your headers and tried to use in your program and pulls them into the exe.

This is why it is not necessary to specifically tell cpp files about each other. The linker will ... well ... link them as needed.

Some things to be aware of: If you define a function twice, you'll get something like "Multiple Definitions" linking error since the linker won't know which to use. If you don't implement a function that you declared and tried to use, you'll get something like an "Unresolved Token" linking error since, obviously, the linker won't be able to find the function definition.

From this you can see that it is possible to have a project that compiles successfully but then fails to link (I hate linking errors [razz]).

Hope that clears things up for you.
NUCLEAR RABBIT
NUCLEAR RABBIT
Thanks for the help guys.

Just one more question:

I made a small test to work with multi files, but something doesnt make sense to me. I have 3 files, 1 header file which has a function definition, and 2 cpp files , main and a message cpp file. The thing that confuses me is i have to create a function prototype in main for the function that is defined in the cpp file, but i dont have to create a prototype in main for the function defined within the header file

main.cpp
#include <iostream>#include "messageh.h"void message();int main(){	Messageh();	message();	return 0;}


messagec.cpp
#include <iostream>void message(){	std::cout << " WORLD!!!\n\n";}


messageh.h
#include <iostream>void Messageh(){	std::cout << "HELLO!";}
yaustar
yaustar
AFAIK, #include is a pre processor call to substitute text from another file. You can literally #include any file (.cpp, files that have no extension (eg iostream).

In you example:
#include <iostream>#include "messageh.h"void message();int main(){	Messageh();	message();	return 0;}


Will become this before compiling:
#include <iostream>// From messageh.h header file#include <iostream>void Messageh(){	std::cout << "HELLO!";}void message();int main(){	Messageh();	message();	return 0;}


Which is why it is valid to call Messageh since the function is defined.
Steven Yau
[Blog] [Portfolio]
speedie
speedie
your going about this a littlr wrong. First of all the use of source file and headers is to help seperate code and speed up compilation if your doing it often.

your header file should not have any definitions of any functions unless you want them to be inline. your sources files are the ones that should have the definitions. and you do know your source and your header have diferent names to them, so they won't link in the right way you want them to.


take your last example, this is how I would organise it.

main.cpp
#include "message.h"int main(){	Message();		return 0;}


message.h
// these are to prevent this file from being compiled more than once#ifndef _MESSAGE_H#define _MESSAGE_H#include <iostream>void message(); // this is just the declaration of the function#endif


message.cpp
#include "message.h"void message(){     std::cout << "HELLO WORLD!!!" << endl;}
-----------------------------------------------The ZoloProject
speedie
speedie
sorry I missread your question in a big way. but shouldn't his code not compile as there's no definition of his function message, as he doesn't include "messagec"?
-----------------------------------------------The ZoloProject
NUCLEAR RABBIT
NUCLEAR RABBIT
so header files are not for definitions, but for declarations. Source files are for the definitions?
rip-off
rip-off
Quote:
Original post by NUCLEAR RABBIT
so header files are not for definitions, but for declarations. Source files are for the definitions?


Yes.

The whole compile/link process is important.

I hope I explain this well.

When you compile a c++ source file, it is compiled independantly of all other files. Every time the preprocessor hits a #include, it literally copies and pastes the contents of that file into the source file. So the compiler sees this ( I am going to reduce the number of functions and class members etc for ease of reading ):

main.cpp
// contents of each of these files will be literally pasted here// you could remove these includes and do the copying and pasting// yourself, there is nothing special about header files.// <iostream> <string> <algorithm> <vector>class Pet{public:	void Talk();};void Wait(){     // do some waiting}int main(){	// use Pet, Pet::Talk and Pause and Wait	return 0;}

pet.cpp
// contents of each of these files will be literally pasted here// you could remove these includes and do the copying and pasting// yourself, there is nothing special about header files.// <iostream> <string> <algorithm> <vector>class Pet{public:	void Talk();};//////////////////////////////////////////////////////////////////////////////////////////    GLOBAL FUNCTION DEFINITION////////////////////////////////////////////////////////////////////////////////////////void Pause(){	// do some pausing}//////////////////////////////////////////////////////////////////////////////////////////    CLASS PET FUNCTION DEFINITIONS////////////////////////////////////////////////////////////////////////////////////////void Pet::Talk(){	// do some talking}


The compiler uses the information found in the file alone to do the compilation. This is when syntax checks occur.

Now, when the compiler is finished, it produces an object file, which is a file designed to let the linker know how to add this code to a larger program. The object file will mention all the names of the externally visible symbols. So class member function names, regular function names and extern variables appear here. Note that class members themselves do not, the members types and addresses can be figured out by the compiler directly, it does not need to store this information past the compilation stage.

Basically the object files list the things that this particular object file provides to the program or needs from the program.

main.cpp can be summed up to the linker as needing all the standard library functions you use, in addition to a function called "Pause" and one called "Pet::Talk" ( note: compilers will mangle the names you give them. this is why when you get linker errors as opposed to compiler errors the names that you made can appear in with lots of letters and numbers ). main.cpp provides the functions called "main" and "wait".

Pet.cpp is similar, it says that it needs all the standard library stuff. It provides the functions Pet::Talk and Pause.

So when the linker starts, it links the name "pause" from pet.o, to the code in pet.o and allows main.o to use it. It does the same for all the other functions.

So when you get linker errors like multiple definitions, it mean the same name is repeated twice. The linker won't look to see if both definitions are the same, it will just complain. Or if one of your object files mentions that it needs something and no other object file provides it, the linker will complain about missing definitions.
NUCLEAR RABBIT
NUCLEAR RABBIT
Quote:
Original post by rip-off
Quote:
Original post by NUCLEAR RABBIT
so header files are not for definitions, but for declarations. Source files are for the definitions?


Yes.

The whole compile/link process is important.

I hope I explain this well.

When you compile a c++ source file, it is compiled independantly of all other files. Every time the preprocessor hits a #include, it literally copies and pastes the contents of that file into the source file. So the compiler sees this ( I am going to reduce the number of functions and class members etc for ease of reading ):

main.cpp
*** Source Snippet Removed ***
pet.cpp
*** Source Snippet Removed ***

The compiler uses the information found in the file alone to do the compilation. This is when syntax checks occur.

Now, when the compiler is finished, it produces an object file, which is a file designed to let the linker know how to add this code to a larger program. The object file will mention all the names of the externally visible symbols. So class member function names, regular function names and extern variables appear here. Note that class members themselves do not, the members types and addresses can be figured out by the compiler directly, it does not need to store this information past the compilation stage.

Basically the object files list the things that this particular object file provides to the program or needs from the program.

main.cpp can be summed up to the linker as needing all the standard library functions you use, in addition to a function called "Pause" and one called "Pet::Talk" ( note: compilers will mangle the names you give them. this is why when you get linker errors as opposed to compiler errors the names that you made can appear in with lots of letters and numbers ). main.cpp provides the functions called "main" and "wait".

Pet.cpp is similar, it says that it needs all the standard library stuff. It provides the functions Pet::Talk and Pause.

So when the linker starts, it links the name "pause" from pet.o, to the code in pet.o and allows main.o to use it. It does the same for all the other functions.

So when you get linker errors like multiple definitions, it mean the same name is repeated twice. The linker won't look to see if both definitions are the same, it will just complain. Or if one of your object files mentions that it needs something and no other object file provides it, the linker will complain about missing definitions.


Thanks a lot for the explination. Im pretty sure i got the concept of this now. [smile]

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.