C++ questions from a java programmer

Started by
4 comments, last by kmart 15 years, 8 months ago
Hello. I'm trying to create some code in C++ but my background training is in Java code. I've got the following code to compile, but I have some questions about it. I'm using Visual Studio 2008 to compile. main.hpp

#ifndef MAIN
#define MAIN

bool isRunning;
int mainChoice;
void printMenu();
#endif


main.cpp

#include <iostream>
using std::cout;
using std::cin;


#include "main.hpp"
#include "newCharacter.hpp"

int main(int argc, char** argv)
{
	isRunning = true;
	mainChoice = 0;
	cout << "\n\n**Welcome to Character Creater for Windows*";
	while(isRunning)
	{
		printMenu();
	
		switch(mainChoice)
		{
			case 1: createNewCharacter();
					break;
			case 2: cout << "\nLoad feature not finished";
					break;
			case 3: isRunning = false;
					break;
			default: cout << "\nInvalid selection";
		}
	}
	cout << "\n\n\nThanks for using Character Creater. \nGoodbye!";
	return 0;
}

void printMenu()
{
	cout << "\n\nMain Menu";
	cout << "\n1. Create New Character";
	cout << "\n2. Load Saved Character";
	cout << "\n3. Exit Character Creater";
	cout << "\nEnter choice: ";
	cin >> mainChoice;
}


newCharacter.hpp

#ifndef NEW_CHARACTER
#define NEW_CHARACTER

//bool isCharacterRunning; <-Won't Work, why not?
//int characterChoice; <-Won't Work, why not?
int displayCharacterMenu();
void createNewCharacter();
#endif


newCharacter.cpp

#include <iostream>
using std::cout;
using std::cin;

#include "newCharacter.hpp"
#include "character.hpp"

void createNewCharacter()
{
	bool isCharacterRunning = true;
	character player;
	int characterChoice;
	
	while(isCharacterRunning)
	{
		characterChoice = displayCharacterMenu();
		switch(characterChoice)
		{
			case 1: player.createName();
					break;
			case 2: cout << "Load class chooser";
					break;
			case 3: cout << "Load major skill choices";
					break;
			case 4: cout << "Load minor skill choices";
					break;
			case 5: cout << "Load point spender";
					break;
			case 6: cout << "Load generic character choices";
					break;
			case 7: cout << "Load history writer";
					break;
			case 8: player.displayName(); 
					break;
			case 9: cout << "Save Character";
					break;
			case 0: isCharacterRunning = false;
					break;
			default: cout << "Invalid option";
		}
	}
}





int displayCharacterMenu()
{
	int returnValue;
	cout << "\n\n\n\n\n***New Character***";
	cout << "\n1. Change Character Name";
	cout << "\n2. Choose character class";
	cout << "\n3. Choose character major skill";
	cout << "\n4. Choose character minor skill";
	cout << "\n5. Spend character points";
	cout << "\n6. Load generic character";
	cout << "\n7. Create Character History";
	cout << "\n8. View Current Stats";
	cout << "\n9. Save Character";
	cout << "\n0. Return to Main Menu";
	cout << "\nEnter Choice: ";
	cin >> returnValue;
	return(returnValue);
}


character.hpp

#ifndef CHARACTER
#define CHARACTER
#include <string>
using std::string;
const int numOfSkills = 8;

class character
{
	
	private:
		string name;
		string skills [numOfSkills];
		int skillvalues [numOfSkills]; 
		int majorSkill;
		int minorSkill;
		int hp;
		int charID;
	public:
		character();
		void createName();
		void displayName();
};
#endif


character.cpp

#include <iostream>
using std::cout;
using std::cin;
#include "character.hpp"

character::character()
{
	
	skills[0] = "Marksmen";
	skills[1] = "Hacking";
	skills[2] = "Piloting";
	skills[3] = "Tatical";
	skills[4] = "Mining";
	skills[5] = "Trading";
	skills[6] = "Persuasion";
}

void character::createName()
{
	cout<<"\nEnter name for character: ";
	cin >> name;
}

void character::displayName()
{
	cout << "\nCharacter Name: " << name;
}


****Questions**** 1. Why do I need to redeclare cout and cin in every file its used? If I don't the project won't compile saying cout and cin are undeclared identifiers. 2. In newCharacter.hpp I can't declare the variables isCharacterRunning and characterChoice. If I do the project errors saying they are already defined in main.obj. This forced me to create variables inside the cpp and pass them through the function. Thanks in advance
Advertisement
Quote:Why do I need to redeclare cout and cin in every file its used?
To be precise, you're declaring them indirectly by including <iostream>. You need to include that everywhere you use cout and cin because the compiler handles source files independently. Code written in one file is not automatically known when compiling other files.

But I think you are referring to using std::cout. That's a using declaration. You don't need it, you can just prefix std, for example std::cout everwhere you use cout. But also, since files are compiled independently, if you have a using declaration in one file, it is not known to other files.

Quote:In newCharacter.hpp I can't declare the variables isCharacterRunning and characterChoice.
Careful. bool isCharacterRunning; is a declaration, but it's also a definition. If you were to write that inside a function, you could then do something like isCharacterRunning=0, which you couldn't if it were only a declaration.

What you want to do is define the global variable in one of your source files, and then have extern bool isCharacterRunning in the header file. You need the keyword "extern" to force a declaration for a variable.

I would caution against global variables though. Just because you can doesn't mean you should. Almost always, creating them within a limited scope of a function and passing them appropriately is a better idea.
Quote:Original post by kmart
1. Why do I need to redeclare cout and cin in every file its used? If I don't the project won't compile saying cout and cin are undeclared identifiers.

I assume you're referring to these lines:
#include <iostream>using std::cout;using std::cin;


You're not declaring[ cin and cout. The 'using' lines simply add std::cout and std::cin into the global namespace. If you didn't have these lines, you could still use cout by using its qualified name, std::cout.

I don't think Java has namespaces yet, so you may not be familiar with them, but put simply, they allow you to define your classes, global variables and functions in different scopes. All of the standard library is defined in the std namespace, which means that to use it, you have to prefix with std::.
This is done to avoid naming collisions.
You can create a variable called 'max' without conflicting with the standard library's std::max function, because it's in a separate namespace.

using std::cout; simply tells the compiler to take cout from the std namespace, and add it to the current namespace, so that in the future, if it sees 'cout' used in this namespace, it actually means std::cout.

But std::cout always existed, so you're not declaring anything. It's not a new variable or anything.

Second, why do you have to do this in every file? Because that's how C++ works. Every .cpp file is compiled independently. The compiler reads one .cpp file, expands all the #includes, evaluates the macros, and ends up with one translation unit which is compiled to one .obj file.
This means that each of these have to make sense in isolation. One .cpp file can't see variables or types defined in another. Hence you need to #include things again, and if you're pulling std::cout into the global namespace, you have to do that in every file as well.

If you define a class, that too must be declared in every .cpp file that uses it (possibly just by including a common header).

This allows the compiler to see that "somewhere, this type exists. I don't know what happens when you call the member functions, but I know they exist, and I know their signatures, so I can generate code to call them".

So when the compiler has run, you're left with a handful of .obj files.
They are passed to the linker, which solves all these dangling references to types that were unknown during compilation. It merges them all together, checks that all these links between compilation units could be resolved, and generates your .exe.

Quote:
2. In newCharacter.hpp I can't declare the variables isCharacterRunning and characterChoice. If I do the project errors saying they are already defined in main.obj. This forced me to create variables inside the cpp and pass them through the function.

This ties in to what I said above as well. Each .cpp file is compiled in isolation. Now, what happens if multiple .cpp files include newCharacter.hpp?
They each see the lines
bool isCharacterRunning;int characterChoice;

and so they create the two variables.

And what happens when the linker merges the two .obj files together? It finds two conflicting definitions of the variables. They have the same names, and are located in the same namespace. What does it do then? How does it know which of the two variables you're referring to?

The solution (if you want to use global variables) is to define the variables in a single .cpp file, and then put 'extern bool isCharacterRunning;' in a header file that all the .cpp files can see.

This way, one .cpp file, and only one, sees the declaration of the variables, and puts them into its .obj file.
All the others only see the 'extern' lines, which essentially mean "this variables will be declared elsewhere, in another .cpp file, but it'll look like this, so you can refer to it if you like".

All the .cpp files should now compile, and when sent to the linker, it sees one declaration of the two variables, and a lot of references to them. And it can handle that. The variable is created in one place only, and everyone else are merely using it.

That said, your current solution is probably better. Globals should generally be avoided.
java does have namespaces, or at the very least packages.

consider

import java.util.*;

that lets us use java.util.HashMap etc...

same basic idea in c++
java does have namespaces, or at the very least packages.

consider

import java.util.*;

that lets us use java.util.HashMap etc...

same basic idea in c++
Thanks for the help everyone. I realized I wasn't actually declaring cout and cin, but I didn't know you had to restate them inside every cpp file.
Now that I know I can move forward.


Thanks again.

This topic is closed to new replies.

Advertisement