C++ OOP - Losing data - c++

I have a few simple classes and I can't get them to work.
TL;DR I have a "Player" instance, after I set some data to the instance, I can get it back. If I push the instance to std::vector Players; if I have Players.at(0).getName() it returns "". The data is not there! Is gone. (Debugging the application I see "_name" set in "vPlayer" and in "Players" I see an element, with "_name" = "")
Here is the code:
//Player.h
#ifndef PLAYER_H
#define PLAYER_H
#include <iostream>
class Player
{
public:
Player();
Player(const Player &Player);
Player& operator=(const Player &Player);
std::string getName();
bool setName(const std::string &name);
bool nameValid(const std::string &name);
private:
std::string _name;
};
#endif
//Player.cpp
#include "Player.h"
#include <iostream>
#include <string>
using namespace std;
Player::Player()
{
}
Player::Player(const Player &Player)
{
}
Player& Player::operator=(const Player &Player) {
return *this;
}
std::string Player::getName()
{
return this->_name;
}
bool Player::setName(const std::string &name)
{
if ( ! this->nameValid(name) )
{
return false;
}
this->_name = name;
return true;
}
bool Player::nameValid(const std::string &name)
{
return name.empty() == false;
}
//Map.h
#ifndef MAP_H
#define MAP_H
#define MAP_X 40
#define MAP_Y 40
#include "Player.h"
#include "Point.h"
#include <vector>
class Map
{
public:
Map();
bool movePlayer(Player &Player, Point &Point);
std::vector<Player> getPlayers();
private:
};
#endif //MAP_H
//Map.cpp
#include "Map.h"
#include "Player.h"
#include "Point.h"
#include <iostream>
#include <string>
using namespace std;
Map::Map()
{
}
bool Map::movePlayer(Player &Player, Point &Point)
{
return true;
}
std::vector<Player> Map::getPlayers()
{
Player vPlayer;
vPlayer.setName(std::string("test"));
std::vector<Player> Players;
Players.push_back(vPlayer);
return Players;
}
in main:
std::vector<Player> Players = vMap.getPlayers();
cout<<"Test:"<<Players.at(0).getName()<<endl;

You define the class's copy constructor and copy assignment operator to do nothing. How do you expect the copy in the vector to have same data as the instance you put into the vector?
Your class can be perfectly fine with the default, compiler-generated copy constructor and copy assignment operator, so just remove your declarations and definitions for them and everything will work.

Your vector will contain copies of the elements you add to it. These copies will be added using Player::Player(const Player&) constructor.
This constructor (in your implementation) doesn't set any value for the name.
Solutions:
set the name in the copied object:
Player::Player(const Player &Player)
: _name(Player._name)
{
}
(The same is true for your assignment operator)
Remove the copy and assignment functionality and rely on the default. Because the name is a std::string, it will get a copy of the source player name by default.

Related

Issues with inheritance and polymorphism

I'm currently learning inheritance and polymorphism in C++, and am coming across this issue when trying to create a child of a parent class that inherits and defines a virtual function.
The goal is for HumanPlayer to be a child of Player, and to create its own implementation of insertion() (a function that inserts an input into a tic-tac-toe board, once complete), however, I have run into a few errors that I can't seem to get by. I'm getting a dwarf error saying
There's an undefined reference to 'vtable for Player'. In function Player::Player() and Player::~Player().
As well as another dwarf error saying
Undefined reference to 'typeinfo for Player'.
Any help with this would be greatly appreciated.
Player.cpp:
#include <iostream>
#include <string>
#include "Player.h"
Player::Player() {
name = "Zoe";
myState = 0;
isWon = false;
}
Player.h
#ifndef PLAYER_H
#define PLAYER_H
class Player {
Player();
protected:
std::string name;
int myState;
bool isWon;
public:
virtual void insertion();
};
#endif
HumanPlayer.h :
#ifndef HUMANPLAYER_H
#define HUMANPLAYER_H
#include "Player.h"
class HumanPlayer : public Player {
public:
HumanPlayer();
void insertion();
protected:
std::string Name1;
std::string Name2;
int humanCheck=0;
std::string getName();
int toInsert;
};
#endif
HumanPlayer.cpp
#include <iostream>
#include <string>
#include "Player.h"
#include "HumanPlayer.h"
HumanPlayer::HumanPlayer() {
if(humanCheck == 0) {
std::cout<<"Player One type your name";
scanf("%s", Name1);
std::cout<<"Player Two type your name";
scanf("%s", Name2);
humanCheck++;
}
}
void HumanPlayer::insertion() {
if(humanCheck % 2 ==0) {
std::cout<<Name2<<"'s turn, please enter an integer between 1 and 7";
scanf("%i", &toInsert);
} else {
std::cout<<Name1<<"'s turn, please enter an integer between 1 and 7";
scanf("%i", &toInsert);
}
humanCheck++;
}

Can't set member data when nested in a class

I'm having this issue on another program, but I tried to simplify it with this one. I cannot set the weapon name through p.getWeaopn().setName("sword"); It works fine when I simply set it through its own object, but when I try to access the setter through player it doesn't set anything.
#include <iostream>
#include <string>
#include "Player.h"
#include "Weapon.h"
using namespace std;
int main()
{
Player p; // Player contains only a Weapon weapon;
Weapon w; // Weapon only contains a string name;
//w.setName("sword"); // this changes the name of the weapon
p.setWeapon(w);
p.weapon.setName("sword"); // this also changes the name
p.getWeapon().setName("sword"); // this is not setting the name. Why?
// checking if weapon has a name
if (p.getWeapon().getName().empty())
{
cout << "Weapon name is empty!" << endl;
}
else
{
cout << "Weapon name is " << p.getWeapon().getName() << endl;
}
}
Weapon.h
#pragma once
#include <string>
using namespace std;
class Weapon
{
private:
string name;
public:
string getName();
void setName(string);
};
Weapon.cpp
#include "Weapon.h"
string Weapon::getName()
{
return name;
}
void Weapon::setName(string n)
{
name = n;
}
Player.h
#pragma once
#include "Weapon.h"
class Player
{
private:
Weapon weapon;
public:
Weapon getWeapon();
void setWeapon(Weapon);
};
Player.cpp
#include "Player.h"
Weapon Player::getWeapon()
{
return weapon;
}
void Player::setWeapon(Weapon w)
{
weapon = w;
}
Weapon Player::getWeapon()
You return a copy and not a reference of the weapon, so any change to the copy does not affect the original.
For return a reference, use & operator:
Weapon& Player::getWeapon()
{
return this->weapon;
}
Player::getWeapon() returns a copy of the weapon every time instead of a reference to the weapon. Changing the name in the copy changes nothing in the original.

Why weird characters shown in cout for string variable in C++?

I have the following code:
Card.h:
#include <string>
using namespace std;
class Card
{
public:
Card(string name);
~Card() {};
string GetName();
private:
string Name;
};
Card.cpp:
#include "Card.h"
using namespace std;
Card::Card(string name) {Name=name;};
string Card::GetName() {return Name;}
Deck.h:
#include "Card.h"
#include <vector>
class Deck {
public:
Card& DrawCard();
void AddCardToDeck(Card& c);
Deck();
~Deck();
private:
std::vector <Card> cardsindeck;
};
Deck.cpp:
#include "Deck.h"
#include <vector>
#include <iostream>
using namespace std;
Card& Deck::DrawCard() {
//cout << cardsindeck.back().GetName()<<" was drawn "<<endl;
Card &c = cardsindeck.back();
cout << c.GetName()<<" was drawn "<<endl;
cardsindeck.pop_back();
cout << c.GetName()<<" popped from deck "<<endl;
return c;
}
Deck::Deck()
{
}
Deck::~Deck()
{
}
void Deck::AddCardToDeck(Card& c) {
cardsindeck.push_back(c);
}
Player.h:
#include "Deck.h"
#include <vector>
using namespace std;
class Player {
public:
void Beginning();
Player(Deck _deck);
~Player() {};
private:
vector <Card> cardsindeck;
Deck deck;
};
Player.cpp:
#include "Player.h"
using namespace std;
Player::Player(Deck _deck)
{
this->deck = _deck;
}
void Player::Beginning()
{
Card& c = deck.DrawCard();
}
main.cpp:
#include "Player.h"
#include <iostream>
#include <string>
using namespace std;
int main()
{
Deck aDeck;
vector <Card> aHand;
Card c=Card("THIS THIS GREAT PLAYER");
Card& c1 =c;
aDeck.AddCardToDeck(c1);
Player P = Player(aDeck);
P.Beginning();
return 0;
}
The output I get is:
THIS THIS GREAT PLAYER was drawn
�\IS GREAT PLAYER popped from deck
Why does the 2nd line have that weird chars in place of "THIS THIS" ?
You have undefined behavior in this function:
Card& Deck::DrawCard() {
// ...
Card &c = cardsindeck.back();
// ...
cardsindeck.pop_back();
cout << c.GetName()<<" popped from deck "<<endl;
return c;
}
First, you alias the last element of cardsindeck with a reference called c. This is fine, and access to its member function is fine, too. Then, you remove the element from the container with cardsindeck.pop_back();. From the docs on std::vector::pop_back, we see that
No iterators or references except for back() and end() are invalidated.
And that's the issue here. You are having a reference to back(), and that is invalidated. It must be - you are deleting the element in the vector that c refers to from the container. Accessing its members then e.g. by GetName() is UB, then.
You can easily fix the issue by copying the return value of cardsindeck.back() like this:
Card c = cardsindeck.back();
// ^^ No reference. The last element is copied
cardsindeck.pop_back(); // Doens't affect the copied instance above
return c;
Note that this requires changing the signature of the member function to
Card Deck::DrawCard()
where the return value is no reference anymore.

error: No matching function for call to class object

Each time I've attempted to build my project, I receive the same error:
>error: no matching function for call to 'Agent::Agent()'
>note: candidates are: Agent::Agent(std::string, room*)
>note: Agent::Agent(const Agent&)
Initially I assumed that I was feeding the wrong values, but even after seemingly correcting, I still get the same error.
main
#include <iostream>
#include <string>
#include <sstream>
#include "room.h"
#include "Thing.h"
//#include "Agent.h"
//#include "Grue.h"
//#include "Player.h"
using namespace std;
int main()
{
srand(time(NULL));
room *entrance = new room("Entrance","A wide open entrance...", 100);
room *hallway = new room("Hallway","A long hallway...", 50);
room *ballroom = new room("Ballroom","A huge ballroom...", 200);
room *garden = new room("Garden","A lush garden...", 150);
entrance->link("south", hallway);
hallway->link("north", entrance);
hallway->link("east", ballroom);
ballroom->link("west", hallway);
ballroom->link("east", garden);
hallway->printLinked();
while(true)
{
for(int i = 0; i < agents.size(); i++)
{
bool ok = agents[i]->act();
if(!ok)
{
cout << "Game quits." << endl;
return 0;
}
}
}
Player *josh = new Player("Josh", entrance);
Player *tracy = new Player("Tracy", entrance);
game.addAgent(josh);
game.addAgent(tracy);
cout << "Welcome!" << endl;
// the step() function in the Game class will eventually
// return false, when a player chooses to quit;
// this tiny "while" loop keeps asking the game.step()
// function if it is false or true; the effect is
// that the step() function is called repeatedly
// until it returns false
while(game.step());
return 0;
}
Thing header
#ifndef THING_H
#define THING_H
#include <iostream>
#include <string>
#include "room.h"
class room;
class Thing
{
private:
std::string name, desc;
protected:
room* cur_room;
public:
Thing(std::string _name, std::string _desc);
std::string getName();
std::string getDesc();
int getSize();
};
#endif // THING_H
Thing cpp
#include "Thing.h"
Thing::Thing(std::string _name, std::string _desc)
{
name = _name;
desc = _desc;
cur_room = NULL;
}
std::string Thing::getName()
{
return name;
}
std::string Thing::getDesc()
{
return desc;
}
int Thing::getSize()
{
return size;
}
Agent header
#ifndef AGENT_H
#define AGENT_H
#include "Thing.h"
#include <iostream>
#include <string>
#include "room.h"
class Agent : public Thing
{
protected:
//bool walk(std::string exit);
room *cur_room;
std::string name;
public:
Agent(std::string _name, room *_cur_room);
void get_curroom();
virtual bool act() = 0;
std::string getName() { return name; }
};
#endif // AGENT_H
Agent cpp
#include "Agent.h"
Agent::Agent(std::string _name, room *_cur_room)
{
name = _name;
room = _cur_room;
}
bool Agent::walk(std::string exit)
{
return 0;
}
bool Agent::act()
{
return 0;
}
void Agent::get_curroom()
{
return cur_room;
}
Player header
#ifndef PLAYER_H
#define PLAYER_H
#include <iostream>
#include <string>
#include "Agent.h"
#include "room.h"
class room;
class Player : public Agent
{
private:
std::string name;
protected:
public:
Player(std::string _name, room *starting_room);
bool Act();
};
#endif // PLAYER_H
Player cpp
#include "Player.h"
Player::Player(std::string _name, room *starting_room)
{
name = _name;
cur_room = starting_room;
}
bool Player::Act()
{
std::cout << "Where do you want to go? (or 'quit')" << std::endl;
}
I'm honestly stumped on where to go next. Any help is greatly appreciated!
In your inheritance chain of Player<-Agent<-Thing, you aren't passing the constructor parameters up to the parent. So, you need to change the Player constructor to:
Player::Player(std::string _name, room *starting_room)
:Agent(_name, starting_room)
{
name = _name;
cur_room = starting_room;
}
And you need to change the Agent constructor to:
Agent::Agent(std::string _name, room *_cur_room)
:Thing(_name, "")
{
name = _name;
room = _cur_room;
}
The parts I added after the colons are called initialization lists. One use of these is to call the constructor of the parent class. In C++, you have to call the parent class's constructor by name, since there is no keyword to reference the parent class generally.
The problem is that in the constructor of Player you don't call the constructor of the base class Agent and the latter doesn't have the default constructor. To fix it call the Agent's constructor (or add the default constructor):
Player::Player(std::string _name, room *starting_room)
: Agent(_name, starting_room)
{
// ...
}

undefined reference to vtable when using interface

I've looked around, and I can't quite figure out where I'm going wrong, as I seem to be following the correct convention when using interfaces, but perhaps I'm overlooking something. The exact error I'm getting is:
undefined reference to `vtable for Icommand'
I've only just begun to seperate my classes and class declarations into separate header files, so perhaps I'm missing a preprocessor directive somewhere.
main.cpp:
#include <iostream>
#include <string>
#include <cstdlib>
#include "Icommand.h"
#include "Command.h"
using namespace std;
void pause();
int main(){
Icommand *run = new Command("TEST");
cout << run->getCommand() << endl;
delete run;
pause();
}
void pause(){
cin.clear();
cin.ignore(cin.rdbuf()->in_avail());
cin.get();
}
Icommand.h:
#ifndef ICOMMAND_H
#define ICOMMAND_H
#include <string>
#include <vector>
class Icommand
{
private:
public:
Icommand(){}
virtual ~Icommand(){}
virtual bool run(std::string object1) = 0;
virtual bool run(std::string object1, std::string object2) = 0;
virtual std::string getCommand() const;
};
#endif // ICOMMAND_H
Command.h:
#ifndef COMMAND_H
#define COMMAND_H
#include <string>
#include <vector>
#include "Icommand.h"
class Command : public Icommand {
private:
std::string command;
std::vector<std::string> synonymns;
Command(); // private so class much be instantiated with a command
public:
Command(std::string command) : command(command){}
~Command(){}
bool run(std::string object1);
bool run(std::string object1, std::string object2);
std::string getCommand() const;
};
#endif // COMMAND_H
Command.cpp:
#include <string>
#include <vector>
#include "Command.h"
bool Command::run(std::string object1){
return false;
}
bool Command::run(std::string object1, std::string object2){
return false;
}
std::string Command::getCommand() const {return command;}
In Icommand.h, replace
virtual std::string getCommand() const;
with
virtual std::string getCommand() const = 0;
to make it pure virtual. Then the compiler can generate a vtable for Icommand. Alternatively, implement Icommand::getCommand.