C++ Pointers In A Game - c++

I am in what seems to be a never ending quest to understand pointers. I finally have a working code using pointers to create a quick character and enemy, then mock an overly simple battle. It works 100% as it seems, but I'm not 100% sure it's correct or what I did to make it right. I have read 13 chapters so far in my C++ book (2 being over pointers specifically), but I'm still not sure it's clicked. If this looks like a valid use and proper utilization of them, I think I'm getting there, just wanted some clarification if it is. Thanks in advance!
#include <iostream>
#include <string>
#ifndef CLASS_H
#define CLASS_H
class Unit
{
public:
Unit(const std::string name, int hp, int power);
~Unit();
void printHP();
void attack(Unit* unit);
bool isDead();
private:
std::string mName;
int mHP;
int mPower;
};
Unit::Unit(const std::string name, int hp, int power)
{
mName = name;
mHP = hp;
mPower = power;
}
void Unit::printHP()
{
std::cout << std::endl;
std::cout << mName << "'s HP: " << mHP << std::endl;
}
void Unit::attack(Unit* unit)
{
std::cout << std::endl;
std::cout << unit->mName << " takes " << this->mPower << " damage! " << std::endl;
unit->mHP -= this->mPower;
}
bool Unit::isDead()
{
return this->mHP < 1;
}
Unit::~Unit()
{
}
#endif
int main()
{
Unit player1("GoodFellow", 20, 5);
Unit Enemy("ABadMan", 10, 2);
while (!Enemy.isDead())
{
player1.printHP();
Enemy.printHP();
player1.attack(&Enemy);
Enemy.attack(&player1);
}
}
Modified it to this... I think I get the reason for only using a reference, just trying to get the concept of pointers....
#include <iostream>
#include <string>
#ifndef CLASS_H
#define CLASS_H
class Unit
{
public:
Unit(const std::string name, int hp, int power);
~Unit();
void printHP();
void attack(Unit& unit);
bool isDead();
void setHP(int hp);
private:
std::string mName;
int mHP;
int mPower;
};
Unit::Unit(const std::string name, int hp, int power)
{
mName = name;
mHP = hp;
mPower = power;
}
void Unit::printHP()
{
std::cout << std::endl;
std::cout << mName << "'s HP: " << mHP << std::endl;
}
void Unit::attack(Unit& unit)
{
std::cout << std::endl;
std::cout << unit.mName << " takes " << this->mPower << " damage! " << std::endl;
unit.mHP -= this->mPower;
}
bool Unit::isDead()
{
return this->mHP < 1;
}
void Unit::setHP(int hp)
{
this->mHP = hp;
}
Unit::~Unit()
{
}
#endif
int main()
{
Unit player1("GoodFellow", 20, 5);
Unit Enemy("ABadMan", 10, 2);
while (true)
{
while (!Enemy.isDead())
{
player1.printHP();
Enemy.printHP();
player1.attack(Enemy);
Enemy.attack(player1);
}
char playAgain;
std::cout << "Fight again? (y)/(n)" << std::endl;
std::cin >> playAgain;
if (playAgain == 'n')
{
break;
}
else
{
Enemy.setHP(10);
}
}
}

Yes, that's a reasonable use of pointers. I was actually glad to see that you used them very little. I was half expecting to see Unit* player1 = new Unit ... and such all over the place. But no, you used automatic storage duration all over (rather than dynamic), which was very appropriate.
So the main reason for passing Unit*s to the attack functions is to that inside the function you can modify the Unit that you're attacking and have the effect seen outside. If you were to pass the Units directly, they would be copied into the function and then the unit->mHP -= this->mPower; would only affect the copy.
However, there is a more appropriate tool at your disposal here. You can use references. A reference also allows you to pass an object without copying it, so that modifications inside the function can be seen outside. Your attack function signature would change to:
void Unit::attack(Unit& unit)
The type Unit& is a "reference to Unit". Don't confuse the use of & with taking the address of an object - it means something completely different here. You would then call it like so:
player1.attack(Enemy);
The point is you should try to avoid pointers as much as possible. Since you can use references here, which are safer (you do not need to check for null), you should use them.
It's fine to learn about how pointers to work, but in doing so, you should learn how to use other more appropriate tools for the job.

Related

Class objects not declared in scope

I am currently experiencing a problem that I just can't seem to wrap my head around why it would be occurring.
In my (Unsplit)program I've created a class that defines an entity object and is able to handle its creation and variables just fine (as I've tested before adding
std::string getName(Entity)const;
std::string getType(Entity)const;
int getDamage(Entity)const;
int getHealth(Entity)const;
But when I do... Even though they are already declared publicly in the class and I am fully able to call Initialize(); Attack(); and PrintStats(); just fine, it doesn't see the other four and therefor are not able to be called.
#include <iostream>
#include <string>
#include <math.h>
#include <stdlib.h> /* srand, rand */
#include <time.h> /* time */
using namespace std;
class Entity
{
public:
Entity() { // default constructor
name = "Human";
type = "Normal";
damage = 1;
health = 100;
}
void printStats();
void Initialize(string, string, int, int); //transformer or setting function
void Attack(Entity&); //observer or getter function
std::string getName(Entity)const;
std::string getType(Entity)const;
int getDamage(Entity)const;
int getHealth(Entity)const;
private://data members and special function prototypes
std::string name;
std::string type;
int damage;
int health;
};
void summonEnemy(Entity&);
int main () {
/* initialize random seed: */
srand (time(NULL));
Entity Player;//declaring new class objects
Entity Enemy;//declaring new class objects
Player.Initialize("Player", "Normal", 10, 90);
summonEnemy(Enemy);
return 0;
}
void summonEnemy(Entity &target) {
target.Initialize("Enemy", "Normal", floor(rand() % 20 + 1), floor(rand() % 100));
cout << "An " << getType(target) << " type " << getName(target) << " has appeared with " <<
getHealth(target) << "HP and can do " << getDamage(target) << " damage.";
}
Error message:
error:'getType' Was not defined in this scope.
error:'getName' Was not defined in this scope.
error:'getHealth' Was not defined in this scope.
error:'getDamage' Was not defined in this scope.
Cut off some code to narrow it down such that only what could be the cause of the problem is showing... But honestly its probably something simple that I am not seeing. Any help appreciated.
You are not calling them correctly. They are members of the Entity class, not standalone functions. Remove the Entity parameters from them, as they already have an implicit Entity *this parameter, and then call them like this:
class Entity
{
public:
Entity(); // default constructor
...
std::string getName() const;
std::string getType() const;
int getDamage() const;
int getHealth() const;
...
};
Entity::Entity()
{
Initialize("Human", "Normal", 1, 100);
}
std::string Entity::getName() const
{
return name;
}
std::string Entity::getType() const
{
return type;
}
int getDamage() const
{
return damage;
}
int getHealth() const
{
return health;
}
void summonEnemy(Entity &target)
{
target.Initialize("Enemy", "Normal", floor(rand() % 20 + 1), floor(rand() % 100));
cout << "An " << target.getType() << " type " << target.getName() << " has appeared with " <<
target.getHealth() << "HP and can do " << target.getDamage() << " damage.";
}
getType is a member function of Entity, so you need to call it on an Entity object:
target.getType();
In the class, you could implement it as:
class Entity {
...
std::string getType() const { return type; }
...
};
The same is true for your other three setters.

C++ constructor variable values at runtime will not be overridden [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 4 years ago.
Improve this question
I am following a c++ course with Unity. I followed the instructor, but I halted at the part where he defines a constructor. For some reason the variables will not be overridden at runtime with the values I gave in the definition of my constructor.
Here is my code:
FBullCowGame.h
#pragma once
//#include <iostream>
#include <string>
class FBullCowGame {
public:
FBullCowGame();
void Reset() const; //TODO make a more rich return value
int GetMaxTries() const;
int GetCurrentTry() const;
bool CheckGuessValidity(std::string) const;
bool IsGameWon() const;
private:
int MyCurrentTry;
int MyMaxTries;
};
FBullCowGame.cpp
#include "FBullCowGame.h"
//#pragma region constructors
FBullCowGame::FBullCowGame() {
int MyCurrentTry = 666;
int MyMaxTries = 666;
}
//#pragma endregion
//#pragma region getters
void FBullCowGame::Reset() const { return; }
int FBullCowGame::GetMaxTries() const { return MyMaxTries; }
int FBullCowGame::GetCurrentTry() const { return MyCurrentTry; }
bool FBullCowGame::CheckGuessValidity(std::string) const { return false; }
bool FBullCowGame::IsGameWon() const { return false; }
//#pragma endregion
main.cpp
#include <iostream>
#include <string>
#include "FBullCowGame.h"
void PrintIntro();
void PlayGame();
std::string GetGuess();
bool AskToPlayAgain();
FBullCowGame BCGame;
int main() {
std::cout << BCGame.GetCurrentTry();
std::cout << BCGame.GetMaxTries();
bool bPlayAgain = false;
do {
PrintIntro();
PlayGame();
bPlayAgain = AskToPlayAgain();
} while (bPlayAgain);
return 0;
}
void PlayGame() {
int MaxTries = BCGame.GetMaxTries();
std::cout << MaxTries << "\n";
for (int i = 1; i <= MaxTries; i++) {
std::string Guess = GetGuess();
std::cout << "Your guess was: " << Guess << std::endl;
std::cout << std::endl;
}
}
void PrintIntro() {
constexpr int WORD_LENGTH = 9;
std::cout << "Welcome to Bulls and Cows, a fun word game.\n";
std::cout << "Can you guess the " << WORD_LENGTH;
std::cout << " letter isogram I'm thinking of?\n\n";
return;
}
//std::cout << "Your guess is: " << Guess << "\n\n";
std::string GetGuess() {
int CurrentTry = BCGame.GetCurrentTry();
std::string Guess = "";
std::cout << "Try " << CurrentTry << ". Enter your guess: ";
std::getline(std::cin, Guess);
return Guess;
}
bool AskToPlayAgain() {
std::cout << "Do you want to play again(y/n)? ";
std::string Response = "";
std::getline(std::cin, Response);
//std::cout << "First char is: " << ((Response[0] == 'y') || (Response[0] == 'Y')) << "\n";
return (Response[0] == 'y') || (Response[0] == 'Y');
}
I a outputting the values with these two lines inside main:
std::cout << BCGame.GetCurrentTry();
std::cout << BCGame.GetMaxTries();
I only get 0 for both values from the getter functions. I am a beginner in c++ and I need a bit of help. I was thinking it's an IDE problem, so I cleaned the solution, rebuilt, rerun, restarted the IDE and did that again. Any kind of help is appreciated. Thanks.
In your class declaration you have:
{
...
private:
int MyCurrentTry;
int MyMaxTries;
};
Then in your constructor you think you are initializing them with this:
FBullCowGame::FBullCowGame() {
int MyCurrentTry = 666;
int MyMaxTries = 666;
}
But what is actually happening here is that you are creating local stack variables with the same exact name as your class's members. Your class member variables can be seen by using the class's this pointer ->:
{
this->MyCurrentTry ...
this->MyMaxTries ...
}
as these two sets of variables are not the same. Your member variables are not even being initialized; the compiler might be smart enough to automatically initialize them with 0 but this isn't guaranteed as they can have any arbitrary value. You are only declaring and initializing stack variables that are local to the constructor only.
To fix this you have 3 options.
First it was already mentioned in the comments. Just remove the type int before the names in the constructor so that you are not declaring local variables but are actually using the members as such:
{
MyCurrentTry = 666;
MyMaxTries = 666;
}
The second option is to do the same but to use the class's this pointer ->
{
this->MyCurrentTry = 666;
this->MyMaxTries = 666;
}
The third and more preferred method is to use the class constructor's member initializer list.
FBullCowGame::FBullCowGame() :
MyCurrentTry( 666 ),
MyMaxTries( 666 ) {
}
This should explain what you was doing wrong within your class's constructor and why the variables were not being initialized to what you thought they should of been, and why you was getting the output you was seeing.
A side note; your class's Reset() function does absolutely nothing.
If you want to use it as you are thinking then you would want it to look like this:
// Remove the const qualifier; otherwise you will not able to modify
// the class's members with this function. "const" is usually good for
// methods that return a member that does not make any internal changes
// to the member or the class.
{
public:
void Reset();
};
FBullCowGame::Reset() {
MyCurrentTry = "whatever value to reset it to."
MyMaxTries = "whatever value to reset it to."
}

I need help separating class code in C++ LNK2005 and LNK1169

I'm new at C++ and I have to create a simple video game, that has an enemy class, the problem comes when I try to separate the enemy code from the main.cpp, creating enemy.h and enemy.cpp, I followed all instructions I saw on the internet but it keeps showing me the error message I hope you guys can help me.
enemy.cpp file
#include "enemy.h"
enemy::enemy(int _hp, int _attackValue, string _name) {
hp = _hp;
attackValue = _attackValue;
name = _name;
}
void enemy::attack(enemy agressor, enemy objective) {
objective.set_hp(objective.hp - agressor.attackValue);
objective.showinfo(objective, 2);
}
void enemy::showinfo(enemy enemy, int hero) {
if (hero == 1) {
cout << " \n\n\n\n\n\n\n";
cout << enemy.name;
cout << " \n\n\n\n\n\n\n\n";
for (int i = enemy.hp / 5; i > 0; i--) {
cout << "|";
}
cout << " \n\n\n\n\n\n\n\n\n";
cout << enemy.hp;
}
else {
cout << " \n\n\n\n\n\n\n";
cout << enemy.name;
cout << " \n\n\n\n\n\n\n\n";
for (int i = enemy.hp / 5; i > 0; i--) {
cout << "|";
}
cout << " \n\n\n\n\n\n\n\n\n";
cout << enemy.hp;
}
}
int enemy::get_hp() {
return hp;
}
void enemy::set_hp(int _hp) {
hp = _hp;
}
int enemy::get_attackValue() {
return attackValue;
}
string enemy::get_name() {
return name;
}
enemy.h file
#pragma once
#ifndef enemy_H
#define enemy_H
class enemy {
private:
int hp, attackValue;
string name;
public:
enemy();
enemy(int, int, string);
void attack(enemy, enemy);
void showinfo(enemy, int);
int get_hp();
void set_hp(int hp);
int get_attackValue();
string get_name();
};
#endif // !enemy_H
PD: I still don't know how to implement setcursorposition in c++ as you can see.
You have declared enemy() but haven't defined it. If you declare the default constructor, make sure you define it (possibly in your .cpp file)
That error that you get means that you violated ODR (one definition rule). In other words, when you tried to separate your enemy class from your main you didn't remote all the parts from there and ended up with the same code in multiple cpp files.
As a side note, looks like you forgot to define your enemy::enemy() constructor, or forgot to move it from main.cpp to enemy.cpp?

C++ string member variable not present in vector

I am creating a vector that contains pointers to a base class. In this vector I'm dynamically storing pointers to derived classes which contain some member variables, one of them being a string variable name.
#include "stdafx.h"
#include <iostream>
#include <vector>
#include <string>
#include <cstdlib>
bool hasDirection = false;
bool hasDiameter = false;
int direction;
float diameter;
int starDimension = 0;
int animalDimension = 0;
int fishDimension = 0;
class MovingObject
{
protected:
std::string name;
int direction;
float diameter;
int dimension;
float movingSpeed;
public:
std::string getName(){ return name;};
int getDirection(){ return direction;};
float getDiameter(){ return diameter;};
float getMovingSpeed(){ return movingSpeed;};
int getDimension(){ return dimension;};
void setName(std::string v){ name = v;};
void setDirection(int d){ direction = d;};
void setDiameter(float f){ diameter = f;};
void setMovingSpeed(float s){ movingSpeed = s;};
void setDimension (int d){ dimension = d;};
virtual void PrintContents()=0;
};
static std::vector<MovingObject*> data;
class starObject : public MovingObject
{
public:
void PrintContents()
{
std::cout << "(" << getName() << "," << getDiameter() << "," << getDirection() << ")";
}
};
class animalObject : public MovingObject
{
public:
void PrintContents()
{
std::cout << "(" << getName() << "," << getDiameter() << "," << getDirection() << ")";
}
};
class fishObject : public MovingObject
{
public:
void PrintContents()
{
std::cout << "(" << getName() << "," << getDiameter() << "," << getDirection() << ", [" << getDimension() << "], " << getMovingSpeed() << ")";
}
};
I later set all these member variables inside a main function. The problem is when I try to output the contents of the member variables, all of them show up except for the string name.
Now, I've checked to make sure that the string gets set before calling the PrintContent() method, and it shows that the value is in the vector. However, when I debug through the code, the value is no longer there, instead containing an empty string.
Could someone with better c++ knowledge explain to me why this is happening? This is the main class:
int main()
{
std::string type;
Reader reader;
while (!std::cin.eof())
{
try
{
std::string type;
std::cin >> type;
if (type =="int")
{
reader.ReadDirection();
}
else if (type =="float")
{
reader.ReadDiameter();
}
else if (type == "string")
{
std::string name;
std::cin >> name;
if (hasDirection && hasDiameter)
{
int dimension;
if (diameter > 0 && diameter < 10)
{
//fish
fishObject fish;
fish.setName(name);
fish.setDiameter(diameter);
fish.setDirection(direction);
dimension = fishDimension;
fishDimension += 50;
fish.setDimension(dimension);
fish.setMovingSpeed(0.1);
data.push_back(&fish);
}
else if (diameter >= 10 < 500)
{
//animal
animalObject animal;
animal.setName(name);
animal.setDiameter(diameter);
animal.setDirection(direction);
dimension = animalDimension;
animalDimension += 800;
animal.setDimension(dimension);
animal.setMovingSpeed(5.0);
data.push_back(&animal);
}
else if (diameter >=500)
{
//star
starObject star;
star.setName(name);
star.setDiameter(diameter);
star.setDirection(direction);
dimension = starDimension;
starDimension += 5000;
star.setDimension(dimension);
star.setMovingSpeed(30.0);
data.push_back(&star);
}
}
else
{
throw (IncompleteData(name));
}
}
}
catch (IncompleteData e)
{
std::cerr << "No diameter or direction given for object " << e.objectName << "\n";
}
}
The objects you push to the data vector are local because they are declared inside if/else blocks (see the declarations of fish and animal).
When you push the address of such an object to the vector, it will continue to point to the local object, which ceases to exist at the end of the local scope. You need to create objects that live beyond the local scope. One way of doing this is to create copies of the local objects on the heap and push those to the vector:
data.push_back(new fishObject(fish));
Of course this means that you get a memory leak unless you make sure you explicitly delete the elements of the vector some time before the end of the program. The usual recommendation to avoid having to think of this is to use a vector of std::unique_ptr<MovingObject> instead of a vector of naked pointers.

or C++: VS2010 multiplication operator being mistaken for a null pointer

I basically have exp>=level*10 in an else if expression, where level is a variable and 10 is a constant number. The code compiles completely fine without any errors, and it even worked after being compiled, until recently. now, whenever it compiles and executes, it gives me an error saying "invalid null pointer" and it conveniently tells me that the problem comes from the included file xstring (VS2010 includes it in new projects) on line 930.
Is there a way to force to program to read it as the multiplication operator instead of a null pointer?
EDIT: Here is my full code, please note that this is a protype created to ensure that it will work and was done prior to me realizing I can use derived classes for this. also note that I tried removing using namespace std to see if that was the problem.
#include "stdafx.h"
#include <iostream>
#include <sstream>
class player {
public:
std::string name;
int hp;
int attack;
int strength;
int defense;
void reward(int gold, int exp) {
player::gold += gold;
player::exp += exp;
player::levelHandler();
}
int dataQuery(std::string query) {
if (query == "equipment")
return helm, armour, greaves;
else if (query == "gold")
return gold;
else if (query == "exp")
return exp;
else if (query == "level")
return level;
else return 0;
}
private:
int helm;
int armour;
int greaves;
int level;
int gold;
int exp;
std::string levelHandler() {
if (level==0) {
level=1;
}
else if (exp>=(10*level)) { //causes problem due to * being mistaken as a
//null pointer.
int previousLevel = level;
level += 1;
levelHandler();
return 0;
};
return 0;
};
} hero;
class enemy {
public:
std::string name;
int hp;
int attack;
int strength;
int defense;
private:
int helm;
int armour;
int greaves;
int level;
int goldReward;
int expReward;
int dataQuery(std::string query) {
if (query == "equipment")
return helm, armour, greaves;
else if (query == "gold")
return goldReward;
else if (query == "exp")
return expReward;
else if (query == "level")
return level;
else return 0;
}
};
int main()
{
std::cout << "Please enter your character's name..." << std::endl;
std::cin >> hero.name;
std::cout << "Welcome to RPG Battle Simulation, " << hero.name << "!" << std::endl;
hero.reward(100, 0); //problem is either this line, or the function's call to levelHandler, as this is where the program terminates.
std::cout << "You are beginning your journey as a level " << hero.dataQuery("level") << " character." << std::endl;
std::cout << "Here is " << hero.dataQuery("gold") << " gold to get you started." << std::endl;
return 0;
};
The following is an excerpt of xstring that is causing the problem. the problem comes from _DEBUG_POINTER(_Ptr); (line 930)
_Myt& assign(const _Elem *_Ptr)
{// assign [_Ptr, <null>)
_DEBUG_POINTER(_Ptr);
return (assign(_Ptr, _Traits::length(_Ptr)));
}
This program reproduces your problem (when compiled with MSVC with runtime that supports debugging):
#include <string>
#include <iostream>
int main()
{
using namespace std;
string s = 0;
cout << s << endl;
}
The problem is that a std::string is initialized with a nullpointer.
EDIT: oh, forgot to mention, solution – simply don’t do that.
Cheers & hth.,