Brian Cowles
Brian Cowles

Reputation: 3

Class object (char) changes after function

I'm pretty new to C++, but this has got me stumped. I'm working on the base code for an RPG, but this one character in the class has got me stumped. I've isolated the pieces at issue here (there's a good 1000 lines cut out), and the problem remains.

Here's the class and header for the program:

#include <iostream>
#include <cstdlib>
using namespace std;

unsigned long errorcount;
// I know this is bad coding, but it's not going to be in the end product...

class character {
public:
  void setgender(char newgender);
  char getgender() const;
private:
  char gender;
};

void character::setgender(char newgender) {
  switch (newgender) {
  case 'M': gender = 'M'; break;
  case 'F': gender = 'F'; break;
  default: gender = '0'; errorcount++; break;
  }
  std::cout << "\nDuring setgender function: " << gender;
  return;
}

char character::getgender() const {
  std::cout << "\nDuring getgender function: " << gender;
  return gender;
}

This next part that has me scratching my head. I started the following code:

void PlayerCharacterCreation(character Player) {
  string newgender;
  while(true) {
    std::cout << "\nAre you male or female?" << "\n1. Male" << "\n2. Female" << "\n::";
    std::cin >> newgender;
    if (newgender == "1") { Player.setgender('M'); break; }
    if (newgender == "2") { Player.setgender('F'); break; }
    std::cout << "\nInvalid response.  Try again.";
  }
  std::cout << "\nAfter setgender function: " << Player.getgender();
}

void PlayerCreationTest() {
  character Test;
  PlayerCharacterCreation(Test);
  char playergender = Test.getgender();
  if (playergender != 'M' && playergender != 'F') { errorcount++; }
  std::cout << "\nAfter getgender function: " << playergender;
  std::cout << "\n\nOUTPUT BEGINS NOW\nGender: " << playergender << "\n";
  std::cout << "OUTPUT ENDS.  Total Errors: " << errorcount << ".";
  return;
}

int main() {
  PlayerCreationTest();
  return 0;
}

Now as far as I can tell, there's nothing wrong with any of this - the (GCC) compiler doesn't complain, and it works just fine up to a point. But if I run it, I get the following output:

Are you male or female?
1. Male
2. Female
1
During setgender function: M
During getgender function: M
After setgender function: M
During getgender function: @
After getgender function: @
OUTPUT BEGINS NOW    
Gender: @
OUTPUT ENDS.  Total Errors: 1.

Worse than that, if I choose option "2" the output is the same only when it makes no sense:

Are you male or female?
1. Male
2. Female
2
During setgender function: F
During getgender function: F
After setgender function: F
During getgender function: @
After getgender function: @
OUTPUT BEGINS NOW
Gender: @
OUTPUT ENDS.  Total Errors: 1.

In other words, the expected output goes badly wrong somewhere between the last line of PlayerCharacterCreation(), and the very next line of the PlayerCreationTest().

As far as I can tell, though, the "character" class should stay the same between functions, not change all willy-nilly like this.

I hope that's enough for someone to figure out what I'm doing wrong, but I was toying with it a little and managed to change the output character even more.

By adding an "srand(0)" line at the beginning of the main function, I can change the '@' to a 'y' for both options 1 and 2.

By adding a "GenderTest()" line at the beginning of the main function, I can change the '@' to a 'F', for both options. If I add both lines, only the one immediately above the "PlayerCreationTest()" line seems to matter. Which is odd, because the full code always returns an 'l' (lowercase L) instead of '@', and the main function is exactly the same as written above.

Upvotes: 0

Views: 120

Answers (2)

kfsone
kfsone

Reputation: 24259

void PlayerCharacterCreation(character Player)

Inside this function, Player is a local instance of character into which the calling parameter is copied. Consider the following:

#include <iostream>

void f1(int x) {
    x++;
}

void f2(int i) {
    i++;
}

int main() {
    int i = 0;
    f(i);
    std::cout << i << '\n';
}

We know that the output from this will be '0', because f1::x and f2::i are their own independent variables copied from our source parameter.

If you want to pass a specific instance of a variable rather than a copy of it, you need to provide a pointer or a reference.

void by_pointer(Character* player) {
    if (player == nullptr) {
        error_handling();
    }
    player->do_thing();
}
by_pointer(&player);

void by_reference(Character& player) {
    player.do_thing();
}
by_reference(player);

Example:

#include <iostream>

int f1(int& param) {
    param++;
}

int main() {
    int i = 0;
    f1(i);
    std::cout << i << '\n';  // outputs 1
}

Upvotes: 1

Rakete1111
Rakete1111

Reputation: 48968

As far as I can tell, though, the "character" class should stay the same between functions, not change all willy-nilly like this.

Well, you're wrong. They do stay the same, because they are seperate variables. PlayerCharacterCreation creates a local character (a copy of Test), and at the end of the function, the object is destroyed.

The original character that you passed to PlayerCharacterCreation never changed, and you get some weird output because the gender was never set for that character.

The Player in PlayerCharacterCreation is a totally new character, it is not Test :)

If you want to modify the character passed to PlayerCharacterCreation, you have to pass it by reference (there are some other ways too, like passing a pointer, returning Player, but that's the best one):

void PlayerCharacterCreation(character& Player);
                                     ^^^
                                  reference

Upvotes: 2

Related Questions