Class function not changing member variable - c++

I'm a beginner in C++ and yesterday i did my first step with the OO (Object Oriented).
I made a programm that has a character class (Personnage), i made three variables for the character, vie, mana and degat.
I made also a function in the class which is attack and it should remove health from john, but when i show the health of john with another function i see 100, can someone help me please ?
#include <iostream>
#include <string>
using namespace std;
class Personnage
{
public:
void montrer()
{
cout << vie << endl;
}
void attaquer(Personnage john)
{
vie = vie - degat;
if (vie < 0)
{
vie = 0;
}
}
private:
int degat = 50;
int vie = 100;
int mana = 100;
};
int main
{
int action(0), degat;
Personnage jack, john;
cout << "What action do you want to do ?" << endl;
cout << "1-Attack your ennemy." << endl;
cout << "2-Take some life" << endl;
cout << "3-Take some mana." << endl;
cin >> action;
switch(action)
case '1':
jack.attaquer(john);
john.montrer();
return 0;
}

First, you must do "case 1" instead of " case '1' " because your variable is integer. However, this wont solve your problem, and you will still see john's state unaffected by the call of the method "attaquer". Why? because method attaquer is invoked on the personnage Jack, not John. If you want the method to change the health of the attacked Paersonnage, not the attacking one, you should make it like this:
void attaquer(Personnage& victime) // notice the &, pass by reference
{
victime.vie -= degat;
if (victime.vie < 0)
{
victime.vie = 0;
}
}

void attaquer(Personnage john)
{
vie = vie - degat;
if (vie < 0)
{
vie = 0;
}
}
vie and degat both refer to the fields of the object the method was called from. You call attaquer from jack, so jack's data changes. You then call john.montrer(), which will show john's untarnished data.
I assume you intended that attaquer affect the Personnage passed to it. To alter the passed parameter:
void attaquer(Personnage john)
{
john.vie = john.vie - degat;
if (john.vie < 0)
{
john.vie = 0;
}
}
You have to specify that you want to use a different object's data. This, however, is not a complete solution because void attaquer(Personnage john) takes a Personnage by value. This means it copies the object you give it, and that new copy disappears at the end of the function. Make it a reference like:
void attaquer(Personnage& john)
This will affect the original object you sent to the function.
Of course, this answer points out that your switch statement is comparing an integer to a character 1 and '1' are two different values.

Related

(C++) Vector elements seem to disappear after for loop ends

I'm extremely new to C++ (even newer to OOP) and I'm doing my first project that doesn't take place within one .cpp file. I've run into a seemingly simple issue where my vector data seems to be disappearing.
Code chunk inside main.cpp's main function:
vector<Horse> HorseStable(horseAmount); // creating an vector of horse objects based on user input horseAmount
for (int i = 0; i < horseAmount; i++) // sets name for each horse and rider
{
string nameString = "";
string riderString = "";
cout << "Enter name for horse #" << (i + 1) << ": ";
cin >> nameString;
HorseStable[i].setName(nameString);
cout << "Enter name for rider of " << nameString << ": ";
cin >> riderString;
HorseStable[i].setRider(riderString);
system("cls");
}
HorseStable[0].printName(); // a test to see if the horse name stayed inside the vector (it did not)
Entire Horse.h file:
#pragma once
#include <iostream>
#include <string>
#include <stdlib.h>
#include <time.h>
class Horse
{
private:
std::string name;
std::string rider;
public:
// these three ints were supposed to be private, but I couldn't access
// maxRunningDistPerSecond as a displayHorse() function parameter from main
// maybe figuring out my first issue will help with this, as I was attempting
// HorseStable[0].displayHorse(maxRunningDistPerSecond)
int maxRunningDistPerSecond;
int distanceTraveled;
int racesWon;
Horse() // default constructor
{
std::string name = " ";
std::string rider = " ";
int maxRunningDistPerSecond = 100;
int distanceTraveled = 0;
int racesWon = 0;
};
int runASecond(int, int);
int sendToGate(int);
void displayHorse(int);
std::string setName(std::string); // sets the horse name based on user input from main.cpp variable
std::string printName(); // simply prints the horse name, I don't believe my issue is here
std::string setRider(std::string);
std::string printRider();
};
Code chunk inside Horse.cpp:
std::string Horse::setName(std::string nameString) // takes user input for horse name
{
Horse::name = nameString;
return std::string(nameString);
}
std::string Horse::printName() // prints the horse's name
{
return std::string(name);
}
setName() and getName() work perfectly within my for loop inside main.cpp, but all data seems to disappear when I attempt them after the loop ends. I've looked for hours for solutions, but had to revert to this stable build after nothing worked. I'm not very good with pointers and passing by reference, but these seem to be the only things that will work. Is it possible that I was using pointers wrong? Should I be creating a vector of Horse pointers, rather than a vector of actual Horse objects?
My other issue:
If you've noticed my public members that are supposed to be private in Horse.h, I cannot access them when private as parameters from functions called in main. This makes some sense, as my function call in main looked like this:
HorseStable[0].displayHorse(distanceTraveled)
I'm not sure how I could refer to each element of the vector within the Horse class, which seems like the only way distanceTraveled would be reachable as private. My professor wants the variables in question to be private, which makes this an issue. The user defines the amount of Horse objects, which means I can't just declare a few named Horses and simply displayHorse(distanceTraveled) them.
Function declaration from Horse.cpp:
void Horse::displayHorse(int distanceTraveled) // attempts to show a graphic of the race progress
{
if (distanceTraveled >= 50)
{
std::cout << "|-> |" << " " << name << ", ridden by " << rider;
}
else if (distanceTraveled >= 100)
{
std::cout << "|--> |" << " " << name << ", ridden by " << rider;
}
else if (distanceTraveled >= 150)
{
std::cout << "|---> |" << " " << name << ", ridden by " << rider;
} // this goes on up to 1000, but this is all that's necessary for posting
I apologize if my formatting isn't up to par, but this assignment has really been stressing me out. I've been understanding all the new material, but it always seems like pointers and referencing are the things that render my assignments unusable.

Question on how I can use and obtain just the value of return after function is executed

I am making a finite state machine for a coding class. How can I use the return value to change the value of int HP in my main so I will not have any other problems with my code. I just want to make it able to manipulate the value of HP, and use the new value of HP for more functions.
Sorry if the fix to this problem is really simple. I am struggling to understand how functions work in C++ and cannot seem to find a solution any other place online or reading tutorials.
#include <iostream>
#include <time.h>
using namespace std;
int forage(int HP) {
cout << "The ant is in foraging state."<<endl;
if (rand() % 100 < 60) {
cout << "The ant found something!"<<endl;
if (rand() % 100 < 10) {
cout << "The ant found poison!" << endl;
HP -= 1;
}
else {
cout << "The ant found food!" << endl;
HP += 1;
}
}
int mHP = HP;
return mHP;
}
int main() {
srand(time(NULL));
int mHP = 0;
cout << "Welcome to Ant Simulator"<<endl;
forage(10);
cout << mHP;
system("pause");
return 0;
}
You have a couple of choices. One possibility is to pass HP by reference, and have forage modify what was passed in:
void forage(int &HP) {
cout << "The ant is in foraging state."<<endl;
if (rand() % 100 < 60) {
cout << "The ant found something!"<<endl;
if (rand() % 100 < 10) {
cout << "The ant found poison!" << endl;
HP -= 1;
}
else {
cout << "The ant found food!" << endl;
HP += 1;
}
}
}
Another possibility is to just use the result returned from forage:
mHP = forage(10);
If you're going to do this, you can add an annotation so that a recent compiler will tell you about the problem if you accidentally ignore the value it returned:
[[nodiscard]] int forage(int HP) {
// ...
The [[nodiscard]] tells the compiler you want to be sure the value returned from this function isn't discarded like your code in the question did.
As an aside, I'd also prefer that forage be separated into a couple of separate pieces. I'd prefer to have one piece that deal strictly with the UI (displaying the strings about what happened) and another that deals strictly with the logic of the game itself. As a starting point, you might consider passing a stream as a parameter, and having forage display to that stream:
void forage(int &HP, std::ostream &s) {
s << "The ant is in foraging state.";
if (rand() % 100 < 60) {
s << "The ant found something!\n";
if (rand() % 100 < 10) {
s << "The ant found poison!\n";
HP -= 1;
}
else {
s << "The ant found food!\n";
HP += 1;
}
}
}
This can help with things like porting the game to work under a windowing system, if you ever decide to do something like that.
Change forage(10); to mHP = forage(10);
Your function forage is of return type int. If you want to get this return value into your variable mHP, you need to assign the return value of the function to the variable as described above.
Just to add to the previous answers... For a basic understanding how a function works with your defined function as an example:
int forage(int HP){...}
The int prior to the function name defines the return type, so basically what your function is giving back at the end of execution.
Then comes the name of your function, in this case forage, followed by the input parameters. In your case there is only one single input parameter which is an integer value int HP. All the code inside of the curly brackets is executed at function call.
Now all functions that do not have the return type void have a return statement somewhere (most of the times at the end) in their code. The actual return value is assigned to a variable like this:
int returnedValue;
receivedValue = forage(10);

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.
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
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
}

Need help outputting things from different functions (C++)

I am fairly new to C++ and coding in general. I am trying to make just a basic little multiple choice type game for practice but I have run into a conundrum.
The program isn't outputting what I want it too. Here is the code:
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <string>
using namespace std;
void sword(int damage);
void fists(int damage);
static int enemyHealth = 250;
int main() {
srand(time(0));
string SOF; //Abreveation for "Sword Or Fists"
cout << "You will be fighting a mean bad guy. Are you using a sword, or your fists?\n";
while (SOF != "sword" && SOF != "fists"){
cout << "Please enter your choice of either 'sword' or 'fists': ";
cin >> SOF;
}
cout << "Okay! Time to fight! \n";
if (SOF == "fists") {
void fists();
}
else if (SOF == "sword") {
void sword();
}
else{ (NULL); }
cout << "Congratulations! You have vanquished that foul beast!\n";
system("pause");
}
//This is for when the user chooses 'sword'
void sword(int damage = rand() % 100 + 50) {
while (enemyHealth > 0){
cout << "You deal " << damage << " damage with your sharp sword. \n";
enemyHealth -= damage;
}
}
//This is for when the user chooses 'fists'
void fists(int damage = rand() % 10 + 4) {
while (enemyHealth > 0){
cout << "You deal " << damage << " damage with your womanly fists. \n";
enemyHealth -= damage;
}
}
The first part works fine, but when I enter my choice of either "fists" or "sword" the output is:
Okay! Time to fight!
Congratulations! You have vanquished that foul beast!
But I want it to output the damage being done with either fists or sword.
If I could get some help with that, it would be amazing. Thanks!
void fists(); is a declaration, not a call, change to fists(); and sword();
Other things to look at:
Default parameters are declared in function declaration before main (or just move whole functions there)
Default parameters in c++ are evaluated once, so all 'hits' will be the same in your code
Local variable names are usually not named in uppercase, SOF looks loke it is a #defined constant or such.
To call the function, don't write void fists();, just
fists();
(What you have is a declaration, which has no useful effect here, rather than a call.)

How to access info from an instance from another instance in c++?

I am just started learning OOP concepts and to help myself learning, I have created a Characters class. From this class I have made instance called main and an instance called monster. Here is the code for the class:
#include <iostream>
#include <string>
using namespace std;
class Character {
public:
string name;
float health;
int attackLevel;
int defenseLevel;
void setAttr(string sName,float sHealth, int sAttackLevel, int sDefenseLevel) {
name = sName;
health = sHealth;
attackLevel = sAttackLevel;
defenseLevel = sDefenseLevel;
}
void attack(int whatInstanceToAttack) {
whatInstanceToAttack.hitpoints -= 20; //obviously not valid but how do i do this?
return whatInstanceToAttack;
}
int defend(string defend) {
int damageRelieved = defenseLevel * 2;
return damageRelieved;
}
};
int main() {
Character main;
Character monster;
main.setAttr("Rafael",200,100,30);
monster.setAttr("Monster1",30,40,30);
cout << "Default Values for Raf are;" << endl;
cout << main.name << endl;
cout << main.health<< endl;
cout << main.attackLevel << endl;
cout << main.defenseLevel << endl;
cout << "Default values for monster are" << endl;
cout <<monster.name << endl;
cout <<monster.health << endl;
cout << monster.attackLevel<< endl;
cout << monster.defenseLevel << endl;
return 0;
}
Basically what I want to do is somehow access the monster instance via the main instance. I want to do this by running the attack method. So if I run
main.attack(monster);
then I want the monster to lose 20 hitpoints.
How do I go about doing this?
All you need is to pass reference of Character in attack method.
I think you must be aware of pass by value and pass by reference concept. If not you can read it here
void attack(Character &whatInstanceToAttack) {
whatInstanceToAttack.hitpoints -= 20; //obviously not valid but how do i do this?
}
Yes you can access the variables of an instance from another instance of the same class. You need to use a reference to the object to ensure the changes are reflected in the other instance. So here is what your attack function should look like.
void attack(Character &c)
{
c.hitpoints - = 20;
}
Now when you call main.attack(monster) from the main() function, the hitpoints of monster will get decremented by 20.
As a side note, it is considered a good practice to make the data members of a class private, to avoid illegal access/modification of the data. Always use the member functions as an interface to your class instances.
overload the method attack and you can pass by value or reference as per your requirement.
void attack(Character chr)
or
void attack(Character &chr)