Deleting an element from a vector - c++

I am new to C++ and I am writing a program that is supposed to simulate a colony of bunnies. The program will be able to add them, give them names, ages, colors, etc. Right now I have a working program that will add bunnies after each pass and age them by 1. How could I make the program delete a bunny once the bunny reaches age 10.
The code:
enter code here
#include <iostream>
#include <ctime>
#include <vector>
#include <cstdlib>
#include <limits>
using namespace std;
const int POSSIBLE_NAMES = 18;
const int POSSIBLE_COLORS = 4;
static std::string possibleNames[] ={
"Jen",
"Alex",
"Janice",
"Tom",
"Bob",
"Cassie",
"Louis",
"Frank",
"Bugs",
"Daffy",
"Mickey",
"Minnie",
"Pluto",
"Venus",
"Topanga",
"Corey",
"Francis",
"London",
};
static std::string possibleColors[] ={
"White",
"Brown",
"Black",
"Spotted"
};
struct Bunny
{
public:
string name;
int age;
string color;
char sex;
Bunny(){
setSex();
setColor();
setAge(0);
setName();
}
int randomGeneration(int x){
return rand() % x;
srand (time(NULL));
}
void setSex()
{
int randomNumber = randomGeneration(2);
( randomNumber == 1 ) ? sex = 'm' : sex = 'f';
}
char getSex()
{
return sex;
}
void setColor()
{
int randomNumber = randomGeneration(POSSIBLE_COLORS);
color = possibleColors[randomNumber];
}
string getColor()
{
return color;
}
void setAge(int age)
{
this->age = age;
}
int getAge()
{
age++;
return age;
}
void setName()
{
int i = randomGeneration(POSSIBLE_NAMES);
name = possibleNames[i];
}
string getName()
{
return name;
}
void deleteBunny(){
if (age > 10){
cout << getName() << " has died" << endl;
}
}
void printBunny()
{
cout << "Name: " << getName() << endl;
cout << "Sex: " << getSex() << endl;
cout << "Color: " << getColor() << endl;
cout << "Age: " << getAge() << endl;
}
};
int main()
{
vector< Bunny > colony;
char quit = '\0';
do
{
// Add more bunny
for (int i = 0; i < 5; i++)
{
colony.push_back(Bunny());
}
// Print all the bunny
for (int i =0; i < colony.size(); i++)
{
colony[i].printBunny();
colony[i].deleteBunny();
cout << endl;
}
cout << "You have a total of " << colony.size() << " bunnies\n";
cout << "Press a key to add more bunny, q to quit\n";
quit = cin.get();
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
// repeat
} while (quit != 'q' && quit != 'Q');
return 0;
}

You have to use erase remove idiom:
std::erase(colony.remove_if( colony.begin(), colony.end(),
[] (bunny& oldBunny){ return oldBunny.age > 10; } ), colony.end());

Each pass you need to check if been is over ten and delete them from the vector.
vector< Bunny > colony;
do
{
for(int i = 0; i < colony.size(); i++){
if(colony[i].getAge() > 10) {
// Call your delete function
colony[i].deleteBunny();
// Delete from vector
colony.erase(colony.begin() + i);
// Shift vector back down
i--;
}
}
// Add more bunny
// Rest of code
}

Related

Creating a vector in class then using class object in function not working

I have a class Employees. I'm trying to make the user insert and delete an employee but it's not working. The size of the vectors should be 500.
class Employees{
public:
int maxx = 500;
vector<string> Surname;
vector<string> FirstName;
vector<string> birthdate;
int vacation[500];
public:
Employees() : Surname(500) {}
};
This is the function that inserts, but printing elements of the vectors is not working at all:
void Process(Employees ZZ){
string dateyear;
string datemonth;
string dateday;
int dateyear1;
int datemonth1;
int dateday1;
int Realage;
int Vacationi = 0;
for(int i = 0; i < 500; i++) {
string s;
cin >> s;
string d;
cin >> d;
string c;
cin >> c;
ZZ.Surname.push_back(s);
ZZ.FirstName.push_back(d);
ZZ.birthdate.push_back(c);
cout << endl << ZZ.Surname[1] << endl;
}
Now the delete function, if I input a string then search for it in the vector then get his index then delete, but the vector doesn't update any values.
void DeleteEmployee(Employees ZZ){
cout<< endl << ZZ.Surname[1] << endl ;
for (int i = 0; i < ZZ.Surname.size(); i++){
cout << ZZ.Surname[i] ;
}
cout << " delete employee";
string delete1;
cin >> delete1;
auto it = std::find(ZZ.Surname.begin(), ZZ.Surname.end(), delete1);
if (it == ZZ.Surname.end())
{
cout<< " name not in vector " << endl;
}
else
{
//auto index = distance(Names.begin(), find(Names.begin(), Names.end(), old_name_)));
//ZZ.Surname.erase(ZZ.Surname.begin()+index) ;
}
}
This is the main function, also the values of the vector are not printing:
int main()
{
Employees ZZ;
Process(ZZ);
DeleteEmployee(ZZ);
cout << "fyccck";
for (int i = 0; i < ZZ.Surname.size(); i++){
cout << ZZ.Surname[i] ;
}
}
There are a lot of things wrong with this code. But the particular issue you are asking about is caused by your functions passing the Employees object by value, so a copy is made, and any changes you make to the copy are not reflected in the original object in main().
You need to change the parameters to pass the Employees object by reference instead:
void Process(Employees &ZZ)
void DeleteEmployee(Employees &ZZ)
That being said, the whole design of the code is not good in general. The vectors are not being kept in sync properly, and for that matter you are using more vectors then you actually need, 1 single vector will suffice. And Process() and DeleteEmployee() should be members of the Employees class, not separate functions. And they are both accessing out-of-bounds of the Surname vector.
I would suggest completely rewriting the code from scratch, for instance something more like this:
struct Employee{
string Surname;
string FirstName;
string BirthDate;
int Vacation;
string DisplayName() const { return Surname + ", " + FirstName; }
};
class Employees{
public:
static const int maxx = 500;
vector<Employee> employees;
Employees() { employees.reserve(maxx); }
bool Add(const Employee &e);
bool Delete(string Surname, string FirstName);
};
bool Employees::Add(const Employee &e) {
if (employees.size() < maxx) {
employees.push_back(e);
return true;
}
return false;
}
bool Employees::Delete(string Surname, string FirstName) {
auto it = std::find_if(employees.begin(), employees.end(),
[&](const Employee &e){
return e.Surname == Surname && e.FirstName == FirstName;
}
);
if (it != employees.end()) {
employees.erase(it);
return true;
}
return false;
}
int main()
{
Employees ZZ;
for(int i = 0; i < Employees::maxx; ++i) {
Employee e;
cin >> e.Surname;
cin >> e.FirstName;
cin >> e.BirthDate;
e.Vacation = 0;//cin >> e.Vacation;
ZZ.Add(e);
cout << endl << e.DisplayName() << endl;
}
cout << " delete employee";
string Surname, FirstName;
if (cin >> Surname >> FirstName) {
if (ZZ.Delete(Surname, FirstName)) {
cout << " name deleted from vector " << endl;
} else {
cout << " name not in vector " << endl;
}
}
cout << "fyccck";
for (auto &e : ZZ.employees) {
cout << e.DisplayName() << endl;
}
return 0;
}

C++ Segmentation fault when trying to insert derived objects into an Object Array

I'm doing a project where we need to create a basic Zoo Tycoon game, in which we create a base class called Animal, 3 derived classes of Animal: Tiger, Penguin, Turtle. We also need to create a Zoo class that holds 3 separate arrays for each animal. I've written up my code but keep getting segmentation faults when compiling. I believe this is due to the way I create my object arrays as well as the method I use for inserting objects into them. I've uploaded my entire code. I apologize for the length. I didn't know what segment I could have uploaded to give a clear idea of what I'm doing.
This is my code
Animal.h
#ifndef ANIMAL_H
#define ANIMAL_H
class Animal
{
private:
int age;
double cost;
int numberOfBabies;
double baseFoodCost;
double payoff;
public:
Animal();
Animal(int, double, int, double, double);
int getAge();
void setAge(int);
double getCost();
void setCost(double);
int getNumberOfBabies();
void setNumberOfBabies(int);
double getBaseFoodCost();
void setBaseFoodCost(double);
double getPayoff();
void setPayoff(double);
};
#endif
Animal.cpp
#include "Animal.h"
Animal::Animal(int a, double c, int n, double b, double p)
{
age = a;
cost = c;
numberOfBabies = n;
baseFoodCost = b;
payoff = p;
}
int Animal::getAge()
{
return age;
}
void Animal::setAge(int a)
{
age = a;
}
double Animal::getCost()
{
return cost;
}
void Animal::setCost(double c)
{
cost = c;
}
int Animal::getNumberOfBabies()
{
return numberOfBabies;
}
void Animal::setNumberOfBabies(int n)
{
numberOfBabies = n;
}
double Animal::getBaseFoodCost()
{
return baseFoodCost;
}
void Animal::setBaseFoodCost(double b)
{
baseFoodCost = b;
}
double Animal::getPayoff()
{
return payoff;
}
void Animal::setPayoff(double p)
{
payoff = p;
}
Tiger.h
#ifndef TIGER_H
#define TIGER_H
#include "Animal.h"
class Tiger: public Animal
{
public:
Tiger();
Tiger(int, double, int, double, double);
};
#endif // !TIGER_H
Tiger.cpp
#include "Tiger.h"
Tiger::Tiger(int age, double cost, int numberOfBabies, double baseFoodCost, double payoff) : Animal(age, cost, numberOfBabies, baseFoodCost, payoff)
{
}
Penguin.h
#ifndef PENGUIN_H
#define PENGUIN_H
#include "Animal.h"
class Penguin: public Animal
{
public:
Penguin();
Penguin(int, double, int, double, double);
};
#endif
Penguin.cpp
#include "Penguin.h"
Penguin::Penguin(int age, double cost, int numberOfBabies, double baseFoodCost, double payoff) : Animal(age, cost, numberOfBabies, baseFoodCost, payoff)
{
}
Turtle.h
#ifndef TURTLE_H
#define TURTLE_H
#include "Animal.h"
class Turtle: public Animal
{
public:
Turtle();
Turtle(int, double, int, double, double);
};
#endif
Turtle.cpp
#include "Turtle.h"
Turtle::Turtle(int age, double cost, int numberOfBabies, double baseFoodCost, double payoff) : Animal(age, cost, numberOfBabies, baseFoodCost, payoff)
{
}
Zoo.h
#ifndef ZOO_H
#define ZOO_H
#include "Animal.h"
#include "Tiger.h"
#include "Penguin.h"
#include "Turtle.h"
#include <cstdlib>
#include <iostream>
using namespace std;
class Zoo
{
private:
Tiger **arrayTiger;
Penguin **arrayPenguin;
Turtle **arrayTurtle;
int sizeTiger, sizePenguin, sizeTurtle;
int capacityTiger, capacityPenguin, capacityTurtle;
double amount;
double revenue;
public:
Zoo();
Zoo(double);
void insertTiger(Tiger);
void insertPenguin(Penguin);
void insertTurtle(Turtle);
void Events();
double getAmount();
void setAmount(double);
void subtractAmount(double);
Tiger** getTigerArray();
Penguin** getPenguinArray();
Turtle** getTurtleArray();
void calculateRevenue();
double getRevenue();
void incrementAge();
void resetRevenue();
};
#endif
Zoo.cpp
#include "Zoo.h"
Zoo::Zoo(double a)
{
amount = a;
capacityTiger = 10;
capacityPenguin = 10;
capacityTurtle = 10;
sizeTiger = 0;
sizePenguin = 0;
sizeTurtle = 0;
revenue = 0;
arrayTiger = new Tiger*[capacityTiger];
arrayPenguin = new Penguin*[capacityPenguin];
arrayTurtle = new Turtle*[capacityTurtle];
}
void Zoo::insertTiger(Tiger t)
{
if (sizeTiger < capacityTiger)
{
arrayTiger[sizeTiger++] = &t;
}
else
{
int oldTigerCapacity = capacityTiger;
capacityTiger *= 2;
Tiger** newArrayTiger = new Tiger* [capacityTiger];
for (int i = 0; i < oldTigerCapacity; i++)
{
newArrayTiger[i] = arrayTiger[i];
}
delete[] arrayTiger;
arrayTiger = newArrayTiger;
arrayTiger[sizeTiger++] = &t;
}
}
void Zoo::insertPenguin(Penguin p)
{
if (sizePenguin < capacityPenguin)
{
arrayPenguin[sizePenguin++] = &p;
}
else
{
int oldPenguinCapacity = capacityPenguin;
capacityPenguin *= 2;
Penguin** newArrayPenguin = new Penguin* [capacityPenguin];
for (int i = 0; i < oldPenguinCapacity; i++)
{
newArrayPenguin[i] = arrayPenguin[i];
}
delete[] arrayPenguin;
arrayPenguin = newArrayPenguin;
arrayPenguin[sizePenguin++] = &p;
}
}
void Zoo::insertTurtle(Turtle turt)
{
if (sizeTurtle < capacityTurtle)
{
arrayTurtle[sizeTurtle++] = &turt;
}
else
{
int oldTurtleCapacity = capacityTurtle;
capacityTurtle *= 2;
Turtle** newArrayTurtle = new Turtle* [capacityTurtle];
for (int i = 0; i < oldTurtleCapacity; i++)
{
newArrayTurtle[i] = arrayTurtle[i];
}
delete[] arrayTurtle;
arrayTurtle = newArrayTurtle;
arrayTurtle[sizeTurtle++] = &turt;
}
}
void Zoo::subtractAmount(double a)
{
amount -= a;
}
double Zoo::getAmount()
{
return amount;
}
void Zoo::setAmount(double a)
{
amount += a;
}
void Zoo::Events()
{
int option = 0;
option = rand() % 4 + 1;
switch(option)
{
case 1: cout << "\n\nA sickness has occurred at the zoo." << endl << endl;
break;
case 2: cout << "\n\nThere has been a boom in zoo attendance." << endl << endl;
break;
case 3: cout << "\n\nA baby animal is born." << endl << endl;
break;
case 4: cout << "\n\nNothing happens." << endl << endl;
break;
}
}
Tiger** Zoo::getTigerArray()
{
return arrayTiger;
}
Penguin** Zoo::getPenguinArray()
{
return arrayPenguin;
}
Turtle** Zoo::getTurtleArray()
{
return arrayTurtle;
}
void Zoo::incrementAge()
{
for(int i = 0; i < sizeTiger; i++)
{
if((arrayTiger[i]->getCost()) == 10000)
{
arrayTiger[i]->setAge((arrayTiger[i]->getAge()) + 1);
}
}
for(int i = 0; i < sizePenguin; i++)
{
if((arrayPenguin[i]->getCost()) == 1000)
{
arrayPenguin[i]->setAge((arrayPenguin[i]->getAge()) + 1);
}
}
for(int i = 0; i < sizeTurtle; i++)
{
if((arrayTurtle[i]->getCost()) == 100)
{
arrayTurtle[i]->setAge((arrayTurtle[i]->getAge()) + 1);
}
}
}
void Zoo::calculateRevenue()
{
for (int i = 0; i < sizeTiger; i++)
{
revenue += (arrayTiger[i]->getPayoff());
}
for (int i = 0; i < sizePenguin; i++)
{
revenue += (arrayPenguin[i]->getPayoff());
}
for (int i = 0; i < sizeTurtle; i++)
{
revenue += (arrayPenguin[i]->getPayoff());
}
}
double Zoo::getRevenue()
{
return revenue;
}
void Zoo::resetRevenue()
{
revenue = 0;
}
main.cpp
#include "Animal.h"
#include "Penguin.h"
#include "Tiger.h"
#include "Turtle.h"
#include "Zoo.h"
#include <iostream>
using namespace std;
int main()
{
const int baseFeedingCost = 10;
Zoo z1(100000);
bool playGame = false;
bool menuExit = false;
char userStart, continueGame, loopPurchase, loopChoice = ' ';
int day = 0;
int initializer = 0;
cout << "\nWelcome to Zoo Tycoon!\n\nIn this game you will manage a zoo business." << endl;
while(!menuExit)
{
cout << "\nA: Play Game" << endl;
cout << "B: Exit" << endl;
cout << "\n\nPlease Select an option: ";
cin.get(userStart);
cin.ignore(INT_MAX, '\n');
if(userStart == 'A' || userStart == 'a') //user selected to start game
{
playGame = true;
menuExit = true;
cout << "\n\nYou will start with $" << z1.getAmount() << " in the bank." << endl;
cout << "\n\nTo begin your Zoo, you must purchase three types of animals (tigers, penguins, turtles)";
cout <<"\nin quantities of either 1 or 2." << endl << endl;
cout << "Please enter you desired number of tigers (1 or 2): ";
cin >> initializer;
if (initializer == 2)
{
Tiger t1(0, 10000, 1, 50, 2000);
z1.insertTiger(t1);
z1.subtractAmount(10000);
Tiger t2(0, 10000, 1, 50, 2000);
z1.insertTiger(t2);
z1.subtractAmount(10000);
cout << "\n\nYou will start with 2 tigers." << endl;
}
else if (initializer == 1)
{
Tiger t1(0, 10000, 1, 50, 2000);
z1.insertTiger(t1);
z1.subtractAmount(10000);
cout << "\nYou will start with 1 tiger." << endl;
}
cout << "\n\nPlease enter you desired number of penguins (1 or 2): ";
cin >> initializer;
if (initializer == 2)
{
Penguin p1(0, 1000, 5, 10, 100);
z1.insertPenguin(p1);
z1.subtractAmount(1000);
Penguin p2(0, 1000, 5, 10, 100);
z1.insertPenguin(p2);
z1.subtractAmount(1000);
cout << "\n\nYou will start with 2 penguins." << endl;
}
else if (initializer == 1)
{
Penguin p1(0, 1000, 5, 10, 100);
z1.insertPenguin(p1);
z1.subtractAmount(1000);
cout << "\n\nYou will start with 1 penguin." << endl;
}
cout << "\n\nPlease enter you desired number of turtles (1 or 2): ";
cin >> initializer;
if (initializer == 2)
{
Turtle tr1(0, 100, 10, 5, 5);
z1.insertTurtle(tr1);
z1.subtractAmount(100);
Turtle tr2(0, 100, 10, 5, 5);
z1.insertTurtle(tr2);
z1.subtractAmount(100);
cout << "\n\nYou will start with 2 turtles." << endl << endl;
}
else if (initializer == 1)
{
Turtle tr1(0, 100, 10, 5, 5);
z1.insertTurtle(tr1);
z1.subtractAmount(100);
cout << "\n\nYou will start with 1 turtle." << endl << endl;
}
cin.ignore(255, '\n');
cin.clear();
}
else if(userStart == 'B' || userStart == 'b')
{
cout << "\nThis game will now exit." << endl << endl;
menuExit = true;
}
else //user inputted invalid response
{
cout << "\n\nI'm sorry but your response is invalid. Please try again." << endl;
cin.ignore(255, '\n');
cin.clear();
}
}
while(playGame) //daily turns that ends when user enters false for playGame
{
loopChoice = loopPurchase = ' ';
z1.incrementAge();
cout << "\n\nDay: " << ++day << endl;
cout << "\nYou have $" << z1.getAmount() << " in the bank";
z1.Events();
cout << "\n\nWould you like to purchase an adult animal? ";
cin.get(loopPurchase);
cin.ignore(INT_MAX, '\n');
if(loopPurchase == 'Y' || loopPurchase == 'y')
{
cout << "\n\nA: Tiger" << endl;
cout << "B: Penguin" << endl;
cout << "C: Turtle" << endl;
cout << "\nPlease choose from the animals listed above: ";
cin.get(loopChoice);
cin.ignore(INT_MAX, '\n');
if(loopChoice == 'A' || loopChoice == 'a')
{
cout << "\n\nYou have chosen to purchase a Tiger" << endl;
Tiger tLoop(3, 10000, 1, 50, 2000);
z1.insertTiger(tLoop);
z1.subtractAmount(10000);
}
else if(loopChoice == 'B' || loopChoice == 'b')
{
cout << "\n\nYou have chosen to purchase a Penguin" << endl;
Penguin pLoop(3, 1000, 5, 10, 100);
z1.insertPenguin(pLoop);
z1.subtractAmount(1000);
}
else if(loopChoice == 'C' || loopChoice == 'c')
{
cout << "\n\nYou have chosen to purchase a Turtle" << endl;
Turtle trLoop(3, 100, 10, 5, 5);
z1.insertTurtle(trLoop);
z1.subtractAmount(100);
}
}
z1.calculateRevenue();
cout << "\n\nYour daily revenue is $" << z1.getRevenue();
//z1.setAmount((z1.getAmount()) + (z1.getProfit()));
z1.resetRevenue();
cout << "\n\nEnd of Day: " << day << ". Would you like to continue? (Enter yes or no): ";
cin.get(continueGame);
cin.ignore(INT_MAX, '\n');
if (continueGame == 'y' || continueGame == 'Y')
{
cout << "\nGame will continue. Proceeding to next day." << endl << endl;
}
else
{
cout << "\n\nYou have chosen to quit the game. Game will now exit." << endl << endl;
playGame = false;
}
}
return 0;
}
The code is huge. I have not reviewed everything.
In Zoo, you define your Animal arrays as:
Tiger **arrayTiger;
Penguin **arrayPenguin;
Turtle **arrayTurtle;
I don't know why a double pointer. Just *arrayTiger, etc. would work. You must also change the Insert method. Instead of assigning &t, just use t.
There are other improvements to make.
In Zoo, the insertTiger (etc), should also subtract amount. You always subtract the amount after calling insert, and you already know the price.
Your wrote almost the same code 3 times for the three animals when initializing arrays of animals. You could check if the input is 1 or 2 (to validate) and then insert animals in a for loop.
Finally. You are not reusing almost anything. You have a lot of repeated code for tigers, turtles and penguins.
Your code is too big as mentioned in the previous answer because of which I couldn't go through the entire code, but the segmentation fault you encounter could be because of the following piece of code :
void Zoo::calculateRevenue()
{
for (int i = 0; i < sizeTiger; i++)
{
revenue += (arrayTiger[i]->getPayoff());
}
for (int i = 0; i < sizePenguin; i++)
{
revenue += (arrayPenguin[i]->getPayoff());
}
for (int i = 0; i < sizeTurtle; i++)
{
revenue += (arrayPenguin[i]->getPayoff());
}
}
If you see here, in the third "for loop", you run the loop till sizeTurtle but are using the arrayPenguin for it. I think this is a mistake and what you wanted to do was something of this sort :
for (int i = 0; i < sizeTurtle; i++)
{
revenue += (arrayTurtle[i]->getPayoff());
}
That being said, they're could be other problems in the code that i am not aware of, but this certainly seems like a candidate to cause a crash in the program.

Making vector of objects by class

I have recently tried to learn how to create an object of vectors in order to represent objects of students including their names and grades. but when I wrote my program I got some errors regarding using &. I do not know what is the problem with my errors. could you please help me to fix it?
#include <iostream>
#include <vector>
#include <string>
using namespace std;
void printvector(const vector< student>&); // fill vector.fill in student information
void fillvector(vector< student>&); // print the information of all students
class student {
public:
student();
student(string, char);
~student();
string getName() ;
char getGrade() ;
void setName(string);
void setGrade(char);
private:
string newName;
char newGrade;
};
student::student() { newGrade = ' '; }
student::student(string name, char grade) {
newName = name;
newGrade = grade;
}
student::~student(){ }
string student::getName() { return newName; }
char student::getGrade() { return newGrade; }
void student::setName(string name) { newName = name; }
void student::setGrade(char grade) { newGrade = grade; }
int main() {
vector<student> myclass;
printvector(myclass);
fillvector(myclass);
return 0;
}
void fillvector(vector< student>& newmyclass) {
string name;
char grade;
int classsize;
cout << "how many students are in your class?";
cin >> classsize;
for (int i = 0; i < classsize; i++) {
cout << "enter student name";
cin >> name;
cout << "enter student grade";
cin >> grade;
student newstudent(name, grade);
newmyclass.push_back(newstudent);
cout << endl;
}
}
void printvector( vector< student>& newmyclass) {
unsigned int size = newmyclass.size();
for (unsigned int i = 0; i < size; i++) {
cout << "student name:" << newmyclass[i].getName() << endl;
cout << endl;
cout << "student grade" << newmyclass[i].getGrade() << endl;
cout << endl;
}
}
It seems you're printing your vector before filling it.. Is your problem fixed when you swap them around?
int main() {
vector<student> myclass;
printvector(myclass); // <--- These two lines should probably be swapped
fillvector(myclass); // <---
return 0;
}

C++ - Vector Segmentation Error

I am currently working on a CMSC project called Blackjack for my college course. I have am trying to add a class called Card to a vector object in another class called Hand. The Hand class is stored as an object in another vector in a class called Player.
My issue is that I try to call the method OutputPlayerHand in a class called Blackjack but I get a segmentation error.
Here is my code for the Blackjack.cpp class.
#include "Blackjack.h"
#include <iostream>
Blackjack::Blackjack()
{
// Initialize the dealer
Player dealer((char *) "Dealer", 100);
m_dealer = dealer;
// Initialize a player 'Jane' with 100 funds
Player player((char *) "Jane", 100);
m_players.push_back(player);
}
Blackjack::Blackjack(char *names[], int numPlayers)
{
// Initialize the dealer
Player dealer((char *) "Dealer", 100);
m_dealer = dealer;
// Loop through all passed player names
for(int i = 0; i < numPlayers; i++)
{
// Initialize a player 'names[i]' with 100 funds
Player player(names[i], 100);
m_players.push_back(player);
}
}
int Blackjack::GetNumPlayers()
{
// Return the size of the players vector
return m_players.size();
}
char *Blackjack::GetPlayerName(int player)
{
// Return the requested player's name
return m_players[player].GetName();
}
int Blackjack::GetPlayerFunds(int player)
{
// Return the requested player's funds
return m_players[player].GetFunds();
}
void Blackjack::SetPlayerFunds(int player, int amt)
{
// Set the requested player's funds
m_players[player].SetFunds(amt);
}
bool Blackjack::SetPlayerBet(int player, int amt)
{
// If the player has insufficient funds
if(m_players[player].GetFunds() < amt)
{
// Return false
return false;
}
// Subtract the amount from the player funds
m_players[player].SetFunds(m_players[player].GetFunds() - amt);
// Add the amount to the player bet
m_players[player].SetBet(amt);
// Return true
return true;
}
void Blackjack::NewDeal()
{
// Create a new unsorted 52 card deck
Deck deck;
// Initialize m_deck to the new deck
m_deck = deck;
// Shuffle m_deck
m_deck.Shuffle();
// 2 cards for dealer, 2 cards for each player
int cardsToDeal = 2 + (2 * m_players.size());
// While we still have cards to deal
while(cardsToDeal > 0)
{
// Deal to each player
for(unsigned int i = 0; i < m_players.size(); i++)
{
std::cout << "Deal Player Card" << std::endl;
// Deal one card to the player
m_players[i].GetHand().AddCard(m_deck.DealCard());
// Decrement the number of cards to deal
cardsToDeal--;
}
std::cout << "Deal Dealer Card" << std::endl;
// Deal the dealer one card
m_dealer.GetHand().AddCard(m_deck.DealCard());
// Decrement the number of cards to deal
cardsToDeal--;
}
}
void Blackjack::OutputPlayerHand(int player)
{
std::cout << "Player Output Card." << std::endl;
m_players[player].GetHand().GetCard(0).OutputCard();
}
void Blackjack::OutputDealerHand()
{
// TODO: Code Method
}
bool Blackjack::HitPlayer(int player)
{
// TODO: Code Method
return false;
}
void Blackjack::DealerPlay()
{
// TODO: Code Method
}
int Blackjack::SettlePlayerBet(int player)
{
// TODO: Code Method
return -1;
}
Here is my code for the Player.cpp class.
#include "Player.h"
Player::Player()
{
m_name = (char *) "Jane";
m_funds = 100;
m_bet = 0;
}
Player::Player(char *name, int funds)
{
m_name = name;
m_funds = funds;
m_bet = 0;
}
char *Player::GetName()
{
return m_name;
}
void Player::SetName(char *name)
{
m_name = name;
}
int Player::GetFunds()
{
return m_funds;
}
void Player::SetFunds(int funds)
{
m_funds = funds;
}
int Player::GetBet()
{
return m_bet;
}
void Player::SetBet(int bet)
{
m_bet = bet;
}
Hand Player::GetHand()
{
return m_hand;
}
Here is my code for the Hand.cpp class.
#include "Hand.h"
void Hand::AddCard(Card card)
{
m_cards.push_back(card);
}
Card Hand::GetCard(int card)
{
return m_cards[card];
}
int Hand::Size()
{
return m_cards.size();
}
void Hand::Clear()
{
m_cards.clear();
}
Here is my code for the main class Proj2.cpp.
/*
* CHANGES TO Blackjack.h SPEC:
* added new member funcs:
* char *GetPlayerName(int)
* int GetNumPlayers()
* void OutputDealerHand()
*
* HitPlayer() should print out the card that was dealt.
*/
#include <cstdlib>
#include <iostream>
#include "Blackjack.h"
using namespace std;
Blackjack *CreateGame(int argc, char *argv[]);
int ProcessArgs(int argCnt, char *args[], char **&names, int *&funds);
void DoNewDeal(Blackjack &game);
void ProcAllBets(Blackjack &game);
void DoAllPlays(Blackjack &game);
void PlayOnePlayer(Blackjack &game, int player);
void SettleAllPlayers(Blackjack &game);
void ShowAllPlayerFunds(Blackjack &game);
bool QueryAnotherRound();
int main(int argc, char *argv[]) {
Blackjack *game;
int round;
cout << "Welcome to CMSC 202 Blackjack!\n";
game = CreateGame(argc, argv);
round = 0;
do {
cout << "\nRound " << ++round << ":\n";
ProcAllBets(*game);
DoNewDeal(*game);
DoAllPlays(*game);
SettleAllPlayers(*game);
ShowAllPlayerFunds(*game);
} while (QueryAnotherRound());
cout << "\nGoodbye!\n";
return 0;
}
Blackjack *CreateGame(int argc, char *argv[]) {
char **names;
int *funds;
int numPlayers;
Blackjack *game;
numPlayers = ProcessArgs(argc - 1, &argv[1], names, funds);
game = new Blackjack(names, numPlayers);
for (int p = 0; p < numPlayers; p++) {
game->SetPlayerFunds(p, funds[p]);
}
return game;
}
int ProcessArgs(int argCnt, char *args[], char **&names, int *&funds) {
int i, p;
int numRecs = argCnt / 2;
names = static_cast<char **>(calloc(numRecs, sizeof(char *)));
funds = static_cast<int *>(calloc(numRecs, sizeof(int)));
for (p = 0, i = 0; p < numRecs; p++) {
names[p] = args[i++];
funds[p] = atoi(args[i++]);
}
return p;
}
void ProcAllBets(Blackjack &game) {
int numPlayers = game.GetNumPlayers();
int bet;
for (int p = 0; p < numPlayers; p++) {
cout << "How much does " << game.GetPlayerName(p) << " bet? ";
cin >> bet;
cout << endl; // For neat scripting
if (!game.SetPlayerBet(p, bet)) {
cout << "Illegal bet--changing to $0\n";
game.SetPlayerBet(p, 0);
}
}
}
void DoNewDeal(Blackjack &game) {
int numPlayers = game.GetNumPlayers();
game.NewDeal();
cout << "The players' hands:\n";
for (int p = 0; p < numPlayers; p++) {
cout << game.GetPlayerName(p) << ": ";
game.OutputPlayerHand(p);
cout << endl;
}
cout << "Dealer: ";
game.OutputDealerHand(); // This hides dealer's hole card
cout << "\n\n";
}
void DoAllPlays(Blackjack &game) {
int numPlayers = game.GetNumPlayers();
int p;
for (p = 0; p < numPlayers; p++) {
PlayOnePlayer(game, p);
}
game.DealerPlay();
}
void PlayOnePlayer(Blackjack &game, int player) {
char *name = game.GetPlayerName(player);
string answer;
bool hit, busted;
cout << ">>" << name << "'s turn:\n";
busted = false;
do {
cout << "Hand: ";
game.OutputPlayerHand(player);
cout << endl;
cout << name << "'s play: ";
cin >> answer;
cout << endl; // For neat scripting
answer[0] == 'y' || answer[0] == 'Y';
hit = (answer[0] == 'h' || answer[0] == 'H');
if (hit) {
busted = game.HitPlayer(player);
}
} while (hit && !busted);
if (busted) {
cout << "Busted!\n";
}
cout << endl;
}
void SettleAllPlayers(Blackjack &game) {
int numPlayers = game.GetNumPlayers();
int p;
for (p = 0; p < numPlayers; p++) {
game.SettlePlayerBet(p);
// Above should print out:
// Joe has busted--Dealer wins", or "Sally has 15--Dealer loses"
}
cout << endl;
}
void ShowAllPlayerFunds(Blackjack &game) {
int numPlayers = game.GetNumPlayers();
int p;
for (p = 0; p < numPlayers; p++) {
cout << game.GetPlayerName(p) << " now has $"
<< game.GetPlayerFunds(p) << endl;
}
cout << endl;
}
bool QueryAnotherRound() {
string answer;
cout << "Another round? ";
cin >> answer;
cout << endl; // For neat scripting
return answer[0] == 'y' || answer[0] == 'Y';
}
Can anyone tell me what I am doing wrong? I am not allowed to edit the Proj2.cpp class in any way. If you need more information please do not hesitate to ask. If you need to see the project in it's entirety here is a link to the Github repository for the entire project so far. If you need to see my project rules and clarifications, here is a link to my courses project description website.
Any help is greatly appreciated on this matter, thank you in advance for your time.
The Hand is empty.
This line: m_players[i].GetHand().AddCard(m_deck.DealCard()) adds a card to a temporary copy only
Make GetHand() return a reference and your players will actually get cards.
Also, you should not include executables like Prog2.out in repositories.

c++ trouble with either RTTI or binary file io

I think I am having trouble with binary file io. If I run my program, create some employee objects and then display them everything works fine. If I save the object data and reload the program I get an RTTI exception. It apears to me that my LoadEmployeeData() and Savelist(vector &e) functions work just fine. The exception occurs in my DisplayEmployeeData() function when I try to use typeid.
Just to reiterate, I am getting an RTTI error when using typeid on an object loaded from disk.
//****************header file***********
#include <string.h>
#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#include <sstream>
#include <typeinfo>
#include <ctime>
#include <cstdlib>
using namespace std;
class Employee
{
private:
int employeeID;
char name[80];
int SSN;
public:
Employee();
Employee(int, char*,int);
virtual ~Employee();
virtual void DisplayBaseData();
//getters
int GetID();
char* getName();
int GetSSN();
//setters
void SetID(int);
void SetName(char*);
void SetSSN(int);
};//end Employee class
class Salary : public Employee
{
private:
double salary;
public:
Salary();
Salary(int, char*, int, double); //id, name, ssn, salary
~Salary();
void DisplayEmployeeData();
//getters
double GetSalary();
//setters
void SetSalary(double);
};//end class Exempt
class Hourly : public Employee
{
private:
double rate;
double hoursWorked;
public:
Hourly();
Hourly(int, char*, int, double, double); //id, name, ssn, rate
~Hourly();
void DisplayEmployeeData();
//getters
double GetRate();
double GetHoursWorked();
//setters
void SetRate(double);
void SetHoursWorked(double);
};//end Hourly Class
const int HOURLYTYPE = 0;
const int SALARYTYPE = 1;
//*******body*******
#include "lab05.h";
Employee::Employee(){};
Employee::Employee(int ID, char* nme, int ssn) : employeeID(ID), SSN(ssn)
{
strcpy(name, nme);
}
int Employee::GetID()
{
return employeeID;
}
char* Employee::getName()
{
return name;
}
int Employee::GetSSN()
{
return SSN;
}
void Employee::SetID(int i)
{
employeeID = i;
}
void Employee::SetName(char* n)
{
strcpy(name, n);
}
void Employee::SetSSN(int i)
{
SSN = i;
}
void Employee::DisplayBaseData()
{
cout << "ID: \t" << employeeID << endl;
cout << "Name: \t " << name << endl;
cout << "SSN: \t" << SSN << endl;
}
Employee::~Employee(){}
Salary::Salary(){}
Salary::Salary(int id, char* nme, int ssn, double slry) : Employee(id, nme, ssn), salary(slry){}
void Salary::DisplayEmployeeData()
{
DisplayBaseData();
cout << "Salary: \t " << salary << endl;
}
double Salary::GetSalary()
{
return salary;
}
void Salary::SetSalary(double d)
{
salary = d;
}
Salary::~Salary(){}
Hourly::Hourly(){}
Hourly::Hourly(int id, char* nme, int ssn, double rte, double worked) : Employee(id, nme, ssn), rate(rte), hoursWorked(worked){}
void Hourly::DisplayEmployeeData()
{
DisplayBaseData();
cout << "Rate: \t" << rate << endl;
cout << "Worked: \t " << hoursWorked << endl;
}
double Hourly::GetRate()
{
return rate;
}
double Hourly::GetHoursWorked()
{
return hoursWorked;
}
void Hourly::SetRate(double d)
{
rate = d;
}
void Hourly::SetHoursWorked(double d)
{
hoursWorked = d;
}
Hourly::~Hourly(){}
vector<Employee*> LoadEmployeeData()
{
vector<Employee*> employeeList;
string fileName = "";
cout << "\nEnter filename for employee data: ";
cin >> fileName;
fstream file;
file.open(fileName, ios::in, ios::binary);
char buffer[4096] = {0};
int numEntries;
file.read((char*)&numEntries, sizeof(int));
cout << numEntries << " number of entries found." << endl;
if (numEntries != 0)
{
int identifier;
for (int i = 0; i < numEntries; i++)
{
file.read((char*)&identifier, sizeof(int));
if (identifier == SALARYTYPE)
{
Employee* temp = new Salary();
file.read((char*)temp, sizeof(Salary));
employeeList.push_back(temp);
}
else if (identifier == HOURLYTYPE)
{
Employee* temp = new Hourly();
file.read((char*)temp, sizeof(Hourly));
employeeList.push_back(temp);
}
}
}
else cout << "No Entries found." << endl;
file.close();
return employeeList;
}//end LoadEmployeeData function
void ListEmployees(vector<Employee*> &e)
{
if (e.size() != 0)
{
for (int i = 0; i < e.size(); i++)
{
if (typeid(*(e[i])) == typeid(Hourly))
{
cout << "\n(" << i << ")" << endl;
dynamic_cast<Hourly*>(e[i])->DisplayEmployeeData();
}
else if (typeid(*(e[i])) == typeid(Salary))
{
cout << "\n(" << i << ")" << endl;
dynamic_cast<Salary*>(e[i])->DisplayEmployeeData();
}
}
}
else cout << "No items in list" << endl;
}// end ListEmployees function
void ModifyEmployee(vector<Employee*> &e)
{
cout << "Enter employee selection." << endl;
}
void CreateEmployee(vector<Employee*> &e)
{
bool continueLoop = true;
srand(time(0)); //seed random number generator
cout << "\n Enter new employee information." << endl;
cout << "Name: ";
char newName[80] = {0};
cin >> newName;
cout << "\n SSN: ";
int newSSN;
cin >> newSSN;
char newType = '-1';
do
{
cout << "\n Is new employee paid a (s)alary or (h)ourly rate? ";
cin >> newType;
if (newType == 's' || newType == 'h') continueLoop = false;
else cout << "incorrect input" << endl;
}while (continueLoop == true);
if (newType == 's')
{
cout << "Enter salary amount: ";
double amount;
cin >> amount;
e.push_back(new Salary(rand() % 1000 + 1, newName, newSSN, amount));
}
else if (newType == 'h')
{
cout << "Enter hourly amount: ";
double amount;
cin >> amount;
cout << "Enter hours worked: ";
double hoursWorked;
cin >> hoursWorked;
e.push_back(new Hourly(rand() % 1000 + 1, newName, newSSN, amount, hoursWorked));
}
}
void Savelist(vector<Employee*> &e)
{
if (e.size() == 0)
cout << "No employees in list. Nothing done." << endl;
else
{
cout << "Enter save filename: ";
char fileName[80] = {'\0'};
cin >> fileName;
fstream* file = new fstream();
file->open(fileName, ios::out, ios::binary);
char buffer[80] = {'\0'};
int numEntries = e.size();
file->write((char*)&numEntries, sizeof(int)); //writes number of entries
for (int i = 0; i < e.size(); i++)
{
if (typeid(*e[i]) == typeid(Salary))
{
int classType = SALARYTYPE;
file->write((char*)&classType, sizeof(int));
file->write((char*)dynamic_cast<Salary*>(e[i]), sizeof(Salary));
}
else if (typeid(*e[i]) == typeid(Hourly))
{
int classType = HOURLYTYPE;
file->write((char*)&classType, sizeof(int));
file->write((char*)dynamic_cast<Hourly*>(e[i]), sizeof(Salary));
}
}
file->close();
}
}
void DeleteEmployee(vector<Employee*> &e)
{
cout << "Input index number of employee to delete: ";
int idx = 0;
cin >> idx;
if (idx > e.size() -1)
cout << "invalid index number\n" << endl;
else
{
delete e[idx];
e.erase(e.begin() + idx); //removes from list
}
}
int main()
{
const int ZERO = 0;
const int ONE = 1;
const int TWO = 2;
const int THREE = 3;
const int FOUR = 4;
const int FIVE = 5;
const int SIX = 6;
int exitMainLoop = false; //for flow control
int mainMenuChoice = -1;
vector<Employee*> employeeList;
do
{
cout << "Select from the following options." << endl;
cout << "(1) Load employee data file." << endl;
cout << "(2) View Employees." << endl;
cout << "(3) Modify Employee data. " << endl;
cout << "(4) Create new employee." << endl;
cout << "(5) Save list to file." << endl;
cout << "(6) Delete employee data. " << endl;
cout << "(0) Exit program." << endl;
//add more options
cout << "Enter selection: ";
cin >> mainMenuChoice;
if (cin.fail())
{
cout << "\nInvalid selection. Try again" << endl;
cin.clear();
string garbage = "";
cin >> garbage;
}
else if (mainMenuChoice == ONE)
employeeList = LoadEmployeeData();
else if (mainMenuChoice == TWO)
ListEmployees(employeeList);
else if (mainMenuChoice == THREE)
ModifyEmployee(employeeList);
else if (mainMenuChoice == FOUR)
CreateEmployee(employeeList);
else if (mainMenuChoice == FIVE)
Savelist(employeeList);
else if (mainMenuChoice == SIX)
DeleteEmployee(employeeList);
else if (mainMenuChoice == ZERO)
exitMainLoop = true;
}while(exitMainLoop == false);
system("PAUSE");
}
You can't read/write raw C++ objects from/to disk if they have virtual methods (or use RTTI, which requires virtual methods) because there's no guarantee that the vtable address from the first execution will be written to disk, and there's no guarantee that the vtable will be in the same place the next time the program is run -- hence, the address that was written to disk will point somewhere incorrect when it is read back.
file->write((char*)dynamic_cast<Hourly*>(e[i]), sizeof(Salary));
looks suspicious. did you mean sizeof(Hourly)?