Public Group

# Problems assigning class variables in switch function

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

## Recommended Posts

I was trying to figure this out myself, but couldn't. This code compiles just fine, until I remove the // in front of ourHero.getClass... I'm unable to set the values in the switch function apparently. Can I use the switch function while still getting my variables set? I'm positive my class is working fine.

#include <iostream> #include <string> #include "Character.h" #include "weapon.h" #include <windows.h> #include "functions.h" using namespace std; character ourHero(); void startScreen(); int main() { startScreen(); cout << "Greetings, adventurer! What be thy name? \n"; string name; cin >> name; void startScreen(); int classChoice; cout << "Which character will you be slaying our foes with?\n" << "1. Fighter\n\n2. Assassin\n\n3. Barbarian\n\n"; cin >> classChoice; switch(classChoice) { case 1: { cout << "\nA fighter! As a fighter you'll be able to wield war axes, battle axes, and" << "... \nwell. Any type of axe you can think up. You'll also be able to wear some of the heavier armor " << "types found here on Anternia."; character ourHero("fighter", 50, 13, 9); break; } case 2: { cout << "\nSo you're an assassin, eh? As an assassin, you'll have less strength than the" << " \nfighter or barbarian, but what you don't have in might, you make up for in \npercision. You will be able " << "to perform certain feats that your counterparts \ncould only dream of doing."; character ourHero("assassin", 30, 8, 14); break; } case 3: { cout << "Great fury! I've not come across many barbarians, but I've never seen such \nfocused rage in any other." << " As a barbarian, you may not be able to sneak through the window of Prince Krism and steal his Gohl Gem, but " << "you will be able to \nknock down the front door before being dragged off to Frorth City Dungeon."; character ourHero("barbarian", 40, 15, 7); break; } default: cout << "Invalid class selection."; } //ourHero.getClass(); cin.get(); return 0; }

##### Share on other sites
The instance ourHero is defined inside the scopes that are defined in the cases. So it is not known outside of it. I would suggest to create a character outside of the switch and initialize it inside of the cases.

##### Share on other sites
As brx mentioned, it looks like you're trying to do something like this:
 int main() { ... character ourHero(); ... switch(classChoice) { ... case barbarian: ourHero = character( "barbarian", 40, 15, 7 ); break; ... } ourHero.getClass(); ... } 
Though it's difficult to tell without knowing what 'character' and the 'getClass' method are doing.

##### Share on other sites
Thanks guys, but I've tried that and it still gives me this error:

main.cpp|54|error: request for member 'getClass' in 'ourHero', which is of non-class type 'character()'|

getClass grabs the string pClass(which is a private member) from the character class. You can actually see I declared it about int main(), but even when it's within int main, it still gives me the same error.

##### Share on other sites
A declaration like: character ourHero(); is considered a function declaration, just like void startScreen(). In this case, it is considered a function called "ourHero" which returns a character and takes no parameters. Functions don't have member variables, so that is the compiler's complaint.

You need to change the declaration to that of a variable. If your class has the appropriate default constructor, either of these forms will work:
 character ourHero; // Or to be explicity character ourHero = character(); 

Another option is to move the switch into a separate function:
 character chooseCharacter() { int classChoice; cout << "Which character will you be slaying our foes with?\n" << "1. Fighter\n\n2. Assassin\n\n3. Barbarian\n\n"; cin >> classChoice; switch(classChoice) { case 1: { cout << "\nA fighter! As a fighter you'll be able to wield war axes, battle axes, and" << "... \nwell. Any type of axe you can think up. You'll also be able to wear some of the heavier armor " << "types found here on Anternia."; return character("fighter", 50, 13, 9); } // ... } // You'll need a default fall back here. // Better still put the above in an loop until the player makes a valid choice! } int main() { startScreen(); cout << "Greetings, adventurer! What be thy name? \n"; string name; cin >> name; character ourHero = chooseCharacter(); // You can now use ourHero.getClass(); // ... } 

##### Share on other sites

I really can't thank you enough. I had actually tried making a separate function but what I didn't know was that I needed to do this: [color=#000000][size=2]character ourHero [color=#666600][size=2]=[color=#000000][size=2] chooseCharacter[color=#666600][size=2]();. Not being able to pull variables out of scopes was holding me back on almost everything I wanted to make. Thanks again!

I might as well mention though... I can getting this warning:

main.cpp|47|warning: control reaches end of non-void function|

Listed line 47 below

#include <iostream> #include <string> #include "Character.h" #include "weapon.h" #include <windows.h> #include "functions.h"

 using namespace std; character chooseClass() { int classChoice; cout << "Which character will you be slaying our foes with?\n" << "1. Fighter\n\n2. Assassin\n\n3. Barbarian\n\n"; cin >> classChoice; switch(classChoice) { case 1: { cout << "\nA fighter! As a fighter you'll be able to wield war axes, battle axes, and" << "... \nwell. Any type of axe you can think up. You'll also be able to wear some of the heavier armor " << "types found here on Anternia."; return character ("fighter", 50, 13, 9); break; } case 2: { cout << "\nSo you're an assassin, eh? As an assassin, you'll have less strength than the" << " \nfighter or barbarian, but what you don't have in might, you make up for in \npercision. You will be able " << "to perform certain feats that your counterparts \ncould only dream of doing."; return character("assassin", 30, 8, 14); break; } case 3: { cout << "Great fury! I've not come across many barbarians, but I've never seen such \nfocused rage in any other." << " As a barbarian, you may not be able to sneak through the window of Prince Krism and steal his Gohl Gem, but " << "you will be able to \nknock down the front door before being dragged off to Frorth City Dungeon."; return character("barbarian", 40, 15, 7); break; } default: cout << "Invalid class selection."; system("cls"); chooseClass(); } } // Line 47 void startScreen(); int main() { startScreen(); cout << "Greetings, adventurer! What be thy name? \n"; string name; cin >> name; void startScreen(); character ourHero = chooseClass(); cout << ourHero.getClass(); cin.get(); return 0; }

##### Share on other sites
If the user does not enter "1", "2" or "3", then the default case will be executed. It appears in the default case you are trying to recursively call the function, and return that result. However, you have omitted the return keyword, which means that the character the recursive invocation returns will be discarded, and you will return potential garbage to the calling function.

The first thing to do is to enable "treat warnings as errors" in your compiler/project settings. Any warning you get as a beginner likely indicates the presence of a bug.

The simplest fix is to then use the return keyword to ensure a correct value is returned.

A better fix is to use a loop: because that is what you actually want to do. Recursion can be a powerful and intuitive way of implementing some algorithms, but it has a hidden limit: the stack. On Windows, the stack defaults to about a megabyte. Sometimes calling a recursive function causes the stack usage to be increased (in other cases the compiler might be clever and re-use existing stack space).
 #include <stdexcept> // ... character chooseClass() { while(true) { int classChoice = 0; cout << "Which character will you be slaying our foes with?\n" << "1. Fighter\n\n2. Assassin\n\n3. Barbarian\n\n"; cin >> classChoice; switch(classChoice) { case 1: { // Fighter message return character ("fighter", 50, 13, 9); } case 2: { // Assassin message return character("assassin", 30, 8, 14); } case 3: { // Barbarian message return character("barbarian", 40, 15, 7); } default: { system("cls"); cout << "Invalid class selection."; break; } } } 
Note that you don't need to use the break keyword when you are returning from the function. I've also initialised "classChoice" to 0, because otherwise it could have any value. If the user was to enter something non-numeric, it might choose a arbitrary class if "classChoice" happened to be a valid value.

Another issue here is that you do not gracefully handle I/O errors. If the user enters "hello", instead of a numeric value, your program will either crash after running out of stack space, or will loop forever, spamming the user's console until they terminate the process.

Error handling in the standard streams is a little tricky, but you only need to understand it once. You can put this logic in a separate function:
 #include <string> #include <limit> #include <iostream> #include <stdexcept> using namespace std; int readInt(const string &prompt) { // Check input stream for validity, and display the prompt while(cin && cout << prompt) { // Try to read a number. Return it if successful. int result; if(cin >> result) { return result; } // Something went wrong, cleanup! cin.clear(); cin.ignore(numeric_limits<streamsize>::max(), '\n'); // Explain what went wrong. cout << "You must enter a number. Please try again.\n"; } // One of our streams is banjaxed if(cout) { throw runtime_error("Bad input stream!"); } else { throw runtime_error("Bad output stream!"); } } 
This is advanced code, but hopefully I can explain what it does. The purpose of this function is to keep asking the user a question until they enter a numeric value. So we take the question as a parameter.

First, we check that cin is valid. The standard streams can be closed or become invalid for a variety of reasons. If you are on Windows, if you type CTRL-Z into the console, you are asking the command prompt to close the standard input stream. The standard output stream can be invalidated for a number of reasons too - it might point at a file or a remote machine, and if the filesystem fills up, or the remote connection closes, the stream becomes unusuable.

Then we attempt to output the prompt. This doubles as the same check for validity as cin. Note this is part of the loop condition, meaning that the prompt will keep being displayed until a valid response has been gathered. Next, we attempt to read a number: if that works, then we can happily return the number.

If not, then we need to "clean up" to try again. First, we clear the error flags in the stream. However, the bad input is still in the buffer. We tell the stream to ignore all the input in it's buffer until we hit a new line. Technically, we can only tell it to ignore input up to a certain number of bytes. But we don't know how much bad data there might be, so we try to grab the maximum amount of a "streamsize".

If either cin or cout becomes invalid, the loop will terminate. In this case, we'll use an exception to signal that an error occurred. The only thing left to do is to discover if it is the input or output streams that are broken, so we can give an accurate error message. If you haven't come across exceptions yet, don't worry about it too much. It would take a determined user to enter this state.

If you prefer, you could use the exit() function here - e.g. exit(1).

With a function like the above, you can write your chooseClass function like this:
 character chooseClass() { while(true) { int classChoice = readInt("Which character will you be slaying our foes with?\n1. Fighter\n\n2. Assassin\n\n3. Barbarian\n\n"); switch(classChoice) { case 1: { // Fighter message return character ("fighter", 50, 13, 9); } case 2: { // Assassin message return character("assassin", 30, 8, 14); } case 3: { // Barbarian message return character("barbarian", 40, 15, 7); } default: { system("cls"); cout << "Invalid class selection."; break; } } } 
All that ugly code in readInt() makes chooseClass() much easier to understand!

##### Share on other sites
That's a little over my head at this point. I tried directly copying that code. My compiler didn't agree with the readInt command. Is there a head file that might make it work?

##### Share on other sites
I hadn't actually tested the code. That function compiles fine for me if you change the header #include <limit> to #include <limits>

##### Share on other sites

That's a little over my head at this point. I tried directly copying that code. My compiler didn't agree with the readInt command. Is there a head file that might make it work?

We generally don't recommend "copypasta" coding, it doesn't help the learning process much using unknown black boxes that people give you, in some cases.

If you have questions about the code or how it operates you should ask, get it clarified and then when you understand what's going on you can reproduce the solution on your own.

• ### Game Developer Survey

We are looking for qualified game developers to participate in a 10-minute online survey. Qualified participants will be offered a \$15 incentive for your time and insights. Click here to start!

• 19
• 36
• 9
• 16
• 75