I'm having this weird issue with a text based RPG I'm trying to create. I'm fairly new to C++, so I thought having a project that I can work on and expand as I learn more would be a good way to put what I have been reading about into actual practice. Today I read about Constructors with arguments.

Before I read this, I had my constructor create my object Player globally, where all it's stats were set to 0. Then there is a point where you have to select between the class Warrior or Mage. Depending on which you choose, another function is called to set all your characters stats to what I wanted to be their defaults.

My book tells me this isn't the best way to do it, since I'm relying on an outside function to set the stats for me, which isn't a good idea in OO programming. So instead, I created the following constructor:

Character(int defStrength=0, int defIntelligence=0, int defAgility=0, int defDefense=0, int defHealth=0, int defLevel=0)
  			{
			cStrength= defStrength; cIntelligence= defIntelligence;  cAgility= defAgility; cDefense= defDefense;
			cHealth= defHealth; cLevel= defLevel;}

It accepts defStrength, DefInt etc as arguments, and then set's the character stats to those.

for(;;){
    
        cout<<"\n\nBefore we begin, please select your class."
	        <<"\nEnter a 'W' for Warrior or an 'M' for Mage. ";
    char classChoice;
    cin>> classChoice;
    
    if(classChoice=='W'|| classChoice=='w'){
	    Character player(5, 2, 3, 3, 10, 1);
  		player.DisplayStats();
  		break;
  		}
   	if(classChoice=='M'|| classChoice=='m'){
   		Character player(2, 5, 3, 2, 10, 1);
	    player.DisplayStats();
	    break;
	   }
	else{
        cout<<"You did not enter a legal value.\n";
        }
}

The new problem, however, is that when my object player is created within the if{ or switch() brackets, when it exits the object is destroyed. ( I added a cout to my destructor just to be sure, and it was indeed executing it) If I take out the if{ or switch() statements, the object works as it should. The only problem is if I do that, I have no idea how I am supposed to code a way to select your class.

The function displayStats() is part of my Character class, and simply couts the values of cStrength, cIntelligence, etc. When the function is called within the if{ brackets, it returns the values as it should, but as soon as it leaves, all the stats are reverted back to 0.

Also, the only way I got my code to compile is to make player global, otherwise when it encounters my first player.memberfunction(), it says first declaration.

Any help would be greatly appreciated.

Why not make a pointer to Character objects in global scope and then, based on the class the user suggest, instantiate said stats?

example...

//in global scope

Character *cPtr; //Notice your constructor isn't called yet
//when user inputs a char..
    char classChoice;
    cin>> classChoice;


    switch(classChoice)
    {
         case 'W':
         case 'w':
                       cPtr = new Character(/*Warrior stats here*/);
                       break;
         case 'M':
         case 'm':
                       cPtr = new Character(/*Mage stats here*/);
                       break;
          default:
                       cout << "Improper selection" << endl;
                       break;

    }

How about adding a new member function, say SetStats(), which takes the user's choice and initializes a default constructed Character, i.e.

// default constructed
Character player;

cout <<"\n\nBefore we begin, please select your class."
	 <<"\nEnter a 'W' for Warrior or an 'M' for Mage. ";

char classChoice;
cin >> classChoice;

// initialize the player according to choice
player.SetStats(classChoice);

player.DisplayStats();

SetStats() might also validate the given choice and return true/false accordingly.

or

// ...
int Strength = 5 ;
int Intelligence = 2 ;
int Agility = 3 ;
int Defense = 3 ;
int Health = 10 ;
int Level = 1 ;

for(;;)
{
  char classChoice ;
  cin >> classChoice ;

  if( classChoice=='W' || classChoice=='w' )
  {
    break ;
  }
  else if( classChoice=='M' || classChoice=='m' )
  {
    Strength = 2 ;
    Intelligence = 5 ;
    Defense = 2 ;
    break;
  }
  else
  {
    cerr << "You did not enter a legal value.\n";
  }
}

Character player( Strength, Intelligence, Agility,
                  Defense, Health, Level ) ;
player.DisplayStats() ;
// ...

It seems a bit pointless to have double the amount of cases than you actually need.

//when user inputs a char..
    char classChoice;
    cin>> classChoice;


    switch(tolower(classChoice))
    {
         case 'w':
                       cPtr = new Character(/*Warrior stats here*/);
                       break;
         case 'm':
                       cPtr = new Character(/*Mage stats here*/);
                       break;
          default:
                       cout << "Improper selection" << endl;
                       break;

    }

Why not make a pointer to Character objects in global scope and then, based on the class the user suggest, instantiate said stats?

If I were to do that, how would I call my member functions with that object?

Also, I thought I didn't want to have to have the program call a member function to set the stats for my object. Maybe I misinterpreted what I was reading, but that seemed to be what the author was saying.

If I were to do that, how would I call my member functions with that object?

Also, I thought I didn't want to have to have the program call a member function to set the stats for my object. Maybe I misinterpreted what I was reading, but that seemed to be what the author was saying.

You would use pointer notation to call member functions, i.e...

cPtr->doSomething(); /*calling the method doSomething in the Character class the pointer is pointing to*/

--and as stated before, you did not call the constructor of the object until the case/break. Therefore your program wasn't directly calling a member function, but rather instantiating said object when "new" was declared.

Does that mean I need a new unique global pointer for each object I want to keep global?

edit: I made two pointers, one for my character and one for the enemies. The enemies are created when you enter battle, and destroyed before returning to the main function. Seems to work perfectly now =)

Does that mean I need a new unique global pointer for each object I want to keep global?

Not necessarily. You could make an object global without making it a pointer, but it seems that you don't want a predefined "reference variable" that calls a particular constructor upon declaration, and furthermore you don't want to have a default constructor then call the member function of that variable at a later time.

If you don't want to mess with pointers, I'd suggest using the "reference variable" technique, otherwise you may have to deal with double pointers, or possible even a container like the vector class that holds character objects.

For example...

#include <vector>
vector<Character> charList; //vector that can hold character objects, declared at global scope

//... code to fill the vector via push_back(Character c)

I'd suggest studying vectors and staying away from double pointers, or you'll end up with a headache.

I can tell you the code for using double pointers, but it would be obnoxiously messy.

Here's a link for the vector class -- http://www.cplusplus.com/reference/stl/vector/

Having the object being stored in a pointer just solved another problem that I was having. Before, any time I wanted to access an individual stat in my class, I had a function like

int Character::DisplayHealth(){
	return cHealth;}
int Character::DisplayStrength(){
	return cStrength;}
int Character::DisplayDefense(){
	return cDefense;}
int Character::DisplayLevel(){
	return cLevel;}

Seemed pretty stupid at the time but it was the only way I could get it to work. Now I just need cPtr->cHealth.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.