I'm trying to return values in a struct after certain conditions the values are initialised as zero but for some reason they don't increment when the condition is met. I'm brand new to c++ and VS so haven't quite got a grip of how to use the debugger properly. I have checked that the values do in fact initialise to zero. I'm assuming the problem must stem from the input to the SubmitGuess method which should take in a string but must not be for some reason failing that the if statements must be incorrect. Sorry my code is riddled with commented out code, comments and is not complete so please ignore that there is code that should be moved or removed etc. Any help would be greatly appreciated and apologies for posting so much code thought it would be easier to just show you rather than trying to explain.
I should also explain I'm using UE4's recommended data types so whenever you see FString it's just a string same with int32 just an int
#include "FISOGame.h"
#include <iostream>
using int32 = int;
//constructor
FGame::FGame()
{
//initialising the private variables so they don't return with an error
//MyCurrentTries = 1;
//MaxTries = 3;
Reset();
}
void FGame::Reset()
{
MyCurrentTries = 1;
MaxTries = 7;
const FString MyHiddenWord = "cat";
return;
}
int FGame::GetMaxTries() const
{
return MaxTries; // gets private variable from header file and returns it
}
int FGame::GetCurrentTries() const
{
return MyCurrentTries;
}
bool FGame::IsGameWon() const
{
// TODO check if game is won
return false;
}
bool FGame::CheckGuessValidity(FString)
{
// TODO check if guess makes sense
return false;
}
// recieves a valid guess, increments turn and returns count
BullCowCount FGame::SubmitGuess(FString Guess)
{
// increment the turn number
MyCurrentTries++;
// setup a return value
BullCowCount BullCowCount;
// get length of hidden word
int32 HiddenWordLength = MyHiddenWord.length();
//loop through all letters of the guess
//compare letters against hidden word
// if they match then
//increment bulls if there in the same place
// increment cows id not
FString Attempt = Guess;
for (int32 MHWChar = 0; MHWChar < HiddenWordLength; MHWChar++) {
for (int32 GChar = 0; GChar < HiddenWordLength; GChar++) {
if (Attempt[GChar] == MyHiddenWord[MHWChar]) {
if (MHWChar == GChar) {
BullCowCount.Bulls++;
}
else {
BullCowCount.Cows++;
}
}
}
}
return BullCowCount;
}
#pragma once
#include <string>
using FString = std::string;
using int32 = int;
//never use using namespace in header file
//struct same as class only variables are defaulted public
// variables initialised to 0
struct BullCowCount {
int32 Bulls = 0;
int32 Cows = 0;
};
class FGame {
public:
//constructor make by reusing class name
// when create instance of class it looks for a constructor and runs whatevers in it
FGame();
public:
int32 GetMaxTries() const; // const if you don't want the method to change anything
int32 GetCurrentTries() const;
void Reset();
bool IsGameWon() const;
bool CheckGuessValidity(FString);
// TODO create method fro counting bulls and cows and increasing turn number
BullCowCount SubmitGuess(FString);
private:
// have to initialise the value to avoid error as it's not been created add comment and recompile to get actual value
// it doesn't pick up the change in the compiler
//see constructor for initialisation
int32 MyCurrentTries;
int32 MaxTries;
FString MyHiddenWord;
};
#include <iostream>
#include <string>
#include "FISOGame.h"
using FText = std::string;
using int32 = int;
//using namespace std; // Don't use using namespace as it makes it difficult to see whats included
// create reference or call for function Game_Ask above the main function or wherever it is called
// must put data type for original function before call this makes it a reference and loads it in to memory first
// same thing as declaring functions in a header file
void Game_Intro();
FText Game_Guess();
void Game_loop();
// make game instance doing this at the top so that it's global and can be accessed by all the functions
// then you can call this instance (NewGameInst) and add a dot to access it functions
FGame NewGameInst; // create an instance of or instantiate // made game but don't know it's data or things it holds
// Entry point for application run
int main() {
Game_Intro();
Game_loop();
system("PAUSE");
return 0;
}
// create function to ask questions declare it outside main
// Either create above call or reference above main to keep main at top
void Game_Intro() {
// introduce the game
constexpr int32 WORD_LENGTH = 6;
std::cout<< "Welcome to guess the ISO word" << std::endl;
std::cout<< "can you guess the " << WORD_LENGTH << " letter ISO word I'm thinking of" << std::endl;
/* // get a guess from the user
FText Guess = "";
std::cout<< "Enter your guess" << std::endl;
std::getline(std::cin, Guess);
std::cout<< "Your guess was " << Guess << std::endl; */
return;
}
FText Game_Guess() {
int32 CurrentGuesses = NewGameInst.GetCurrentTries(); // gets the current try
//std::cout << CurrentGuesses << std::endl; // print the current try
// get a guess from the user
FText Guess = "";
std::cout << "Attempt number : " << CurrentGuesses << std::endl;
std::cout << "Make a guess" << std::endl;
std::getline(std::cin, Guess);
return Guess;
}
void Game_loop() {
// make game instance
//FGame NewGameInst; // create an instance of or instantiate // made game but don't know it's data or things it holds
int32 TRIES = NewGameInst.GetMaxTries(); // replaces need for the constant TRIES vvvv
// constexpr int32 TRIES = 5; // number of tries variable
std::cout << TRIES << std::endl;
// loops for number of avaiable guesses
// TODO change it from for to while loop
for (int32 Guesses = 1; Guesses <= TRIES; Guesses++) {
FText Guess = Game_Guess();
// TODO Submit valid guess to game
BullCowCount BullsCows = NewGameInst.SubmitGuess(Guess);// submit guess and place in to instance of struct BullCowCount
// TODO Print number of bulls and cows
std::cout << "Bulls : " << BullsCows.Bulls;
std::cout << " Cows : " << BullsCows.Cows << std::endl;
std::cout << std::endl;
//std::cout<< "Your guess was : " << Guess << std::endl; // TODO make loop for checking valid answer
//std::cout<< std::endl;
if (Guesses == TRIES) {
std::cout<< "Nice try sorry you're out of guesses" << std::endl;
FText Answer = " ";
std::cout<< "would you like another go? : Y/N " << std::endl;
std::getline(std::cin, Answer);
if (Answer == "Y" || Answer == "y") {
NewGameInst.Reset();
Game_loop();
}
else {
std::cout<< "Thanks for playing" << std::endl;
}
}
}
return;
}
I can spot one issue. May not be your only issue. But here's a fix to start with.
Your Reset method defines a local variable of MyHiddenWord which gets discarded when Reset returns. The actual member variable of the FGame class, MyHiddenWord, never gets initialized.
void FGame::Reset()
{
MyCurrentTries = 1;
MaxTries = 7;
const FString MyHiddenWord = "cat"; // this is just a local variable
return;
}
I suspect you meant this:
void FGame::Reset()
{
MyCurrentTries = 1;
MaxTries = 7;
MyHiddenWord = "cat"; // actually initializes the member variable of FGame
return;
}
Related
I have the following problem: I wanted to redo a project from good old C to C++ and make everything class(y) :) and keep it scalable from the beginning.
It is a simulation of cells (being part of a swarm) on a grid, so I decided the following structure:
class Simulation has an instance of
class Grid has an instance of
class Swarm has an instance of
class Cell
I defined the classes in separate header files. Then I need, of course, to be able to call functions in grid, swarm and cell as well. I wanted to do it straight forward:
Simulation mysim;
mysim.get_grid(0).any_function_here();
with the grid as return parameter
Grid Sim::get_grid(int grid_no)
{
std::cout << "sim.get_grid(" << grid_no << ") called." << std::endl;
if (grid_no <= amount_of_grids)
return this->test;//##//this->gridlist[grid_no];
else
std::cout << "you have not created this grid number yet" << std::endl;
Grid dummy;
return dummy;
}
It calls the function and works as long as no changes in the grid are made. These seem to be lost in space. Probably a pointer error, but I cannot find an error, since exactly the same code is working for the Simulation class...
More source:
int Grid::create_swarm(std::string name)
{
Swarm new_swarm;
new_swarm.set_name("Protoswarm");
swarmlist.push_back(new_swarm);
this->amount_of_swarms ++;
std::cout << "amount_of_swarms = " << amount_of_swarms << std::endl;
return 0;
}
Swarm Grid::get_swarm(int swarm_no)
{
std::cout << "grid.get_swarm(" << swarm_no << ") called." << std::endl;
if (swarm_no <= amount_of_swarms)
return swarmlist[swarm_no];
else
std::cout << "oh oh - you have not this swarm in here..." << std::endl;
Swarm dummy;
return dummy;
}
I can call the create_swarm function as often as I want, but the swarms do never appear and the counter does not raise in that grid, just temporarily as long as the funtion is in there. Am I missing something? Is it really just a pointer error? Why does this code work if I call it like this:
Grid newgrid;
newgrid.create_swarm();
A quickly c&p'ed MWE
#include <iostream>
#include <string>
#include <vector>
class Sim
{
public:
Sim();
virtual ~Sim();
Grid get_grid(int grid_no);
protected:
private:
std::vector<Grid> gridlist;
int amount_of_grids = -1;
};
class Grid
{
public:
Grid();
virtual ~Grid();
int set_size(int x, int y);
int create_swarm(std::string name);
Swarm get_swarm(int swarm_no);
void print_swarms();
protected:
private:
std::vector<Swarm> swarmlist;
int amount_of_swarms = -1;
/*static const*/ int size_x;
/*static const*/ int size_y;
std::vector<std::vector<Field>> fields;
std::string gridname;
};
Grid Sim::get_grid(int grid_no)
{
std::cout << "sim.get_grid(" << grid_no << ") called." << std::endl;
if (grid_no <= amount_of_grids)
return this->gridlist[grid_no];
else
std::cout << "you have not created this grid number yet" << std::endl;
Grid dummy;
return dummy;
}
int Grid::create_swarm(std::string name)
{
Swarm new_swarm;
new_swarm.set_name("Protoswarm");
swarmlist.push_back(new_swarm);
this->amount_of_swarms ++;
std::cout << "amount_of_swarms = " << amount_of_swarms << std::endl;
return 0;
}
Swarm Grid::get_swarm(int swarm_no)
{
std::cout << "grid.get_swarm(" << swarm_no << ") called." << std::endl;
if (swarm_no <= amount_of_swarms)
return swarmlist[swarm_no];
else
std::cout << "oh oh - you have not this swarm in here..." << std::endl;
Swarm dummy;
return dummy;
}
using namespace std;
int main(int argc, char* argv[])
{
Sim mysim;
mysim.create_grid();
mysim.get_grid(0).create_swarm("Alpha-Swarm");
mysim.get_grid(0).create_swarm("Betaa-Swarm"); //doesn't work
Grid newgrid;
newgrid.create_swarm("Gamma-Swarm");
newgrid.create_swarm("Delta-Swarm"); // works, but is not needed.
return 0;
}
Grid Sim::get_grid(int grid_no) {...}
You are returning by value, not by reference. That means that what you are returning is a copy of your actual member. In your case, however, you want to be returning by reference in order to be able to make changes to the original object. Your code would become
Grid& Sim::get_grid(int grid_no) {...}
Keep in mind, however, that you will not be able to return any temporaries that way (such as your dummy Grid), so you will need to change your methods to circumvent this issue. If you do not want to do this, you could still return a pointer, although this would change the syntax a little.
Your get_grid and get_swarm methods return copies of original array items. You should return reference (or a pointer) to Grid or Swarm instead.
I made a class called "Item" and a class called "Room" and there's a vector for Item types called "Items" inside Room.
I added a few Items into the Item vector and tried to make a getter for that Item Vector. Now i'm trying to print the getter to see if it really did get what i wanted but it gives me an error message when i try one way or just prints nothing when i try a different way. What am i doing wrong?
Room.h has some stuff as well as these lines of code:
.....
///Getters
//get a list of the items currently in the room
vector<Item> GetItems();
private:
///properties
string RoomName;
string RoomDescription;
vector <Door> Doors;
vector <Item> Items;
Room.cpp has things that defined default and overloaded rooms and gave rooms some items and also has these:
vector<Item>Room::GetItems()
{
return Items;
}
int Room::GetItemAmount()
{
return Items.size();
}
main.cpp has some push.backs and stuff and it appears that the items are properly contained in the vector. Now i'm not sure how to print the getter for it it... trying this:
Room FunStoneRoom = Room();
FunStoneRoom.AddItem(ItemCharcoal);
for (unsigned int VectorPos = 0; VectorPos < FunStoneRoom.GetItemAmount(); VectorPos++)
{
cout << FunStoneRoom.GetItems[VectorPos] << " ";
}
cout << endl;
This gives me an error :
Severity Code Description Project File Line Suppression State
Error C3867 'Room::GetItems': non-standard syntax; use '&' to create a pointer to member ConsoleApplication25 d:\tiltan\visual studio\ownclasses\room+item+door\consoleapplication25\main.cpp 51
I also tried:
for (unsigned int VectorPos = 0; VectorPos < FunStoneRoom.GetItemAmount(); VectorPos++)
{
FunStoneRoom.GetItems()[VectorPos];
}
cout << endl;
which doesn't give an error but just prints an empty line.
and:
for (unsigned int VectorPos = 0; VectorPos < FunStoneRoom.GetItemAmount(); VectorPos++)
{
cout << FunStoneRoom.GetItems()[VectorPos];
}
cout << endl;
which marks my << with a red line and tells me no operator "<<" matches these operands...
How do i go about this?
I'm really not that advanced and don't know a lot of complicated functions and codes and whatnot so please try to be as simple as u can with me.
i'm also new here so sorry if i'm not posting or explaining myself properly...
EDIT: per requested - i'm adding item.h and item.cpp but remember i don't need to know what they contain, only a list of the items in the vector:
item.h:
#pragma once
#include <string>
#include <iostream>
using namespace std;
class Item
{
public:
///constructors
Item(); //default item
///overloadeds
//overloaded customizable items
// #param string = Item Name
// #param string = Item Description
Item(string, string);
///destructors
~Item();
///methods
//Display item name and description
void ViewItem();
//Set a new Item Description
void SetItemDescription(string);
//Set a new Item Name
void SetItemName(string);
//Get an Item's name
string GetItemName();
//Get an Item's description
string GetItemDescription();
private:
///properties
string ItemName;
string ItemDescription;
};
item.cpp:
#include "Item.h"
Item::Item()
{
Item::ItemName = "Non Material Item";
Item::ItemDescription = "You cannot see, feel, taste, smell or hear this item";
}
Item::Item(string NewItemName, string NewItemDesc)
{
NewItemName[0] = toupper(NewItemName[0]);
Item::ItemName = NewItemName;
Item::ItemDescription = NewItemDesc;
}
Item::~Item()
{
}
void Item::ViewItem()
{
cout << ItemName << endl;
cout << ItemDescription << endl;
}
void Item::SetItemDescription(string NewItemDescription)
{
if (NewItemDescription.length() < 100)
{
NewItemDescription[0] = toupper(NewItemDescription[0]);
ItemDescription = NewItemDescription;
}
else
{
ItemDescription = "This Item's description is too long";
}
}
void Item::SetItemName(string NewItemName)
{
if (NewItemName.length() < 30)
{
NewItemName[0] = toupper(NewItemName[0]);
ItemName = NewItemName;
}
else
{
ItemDescription = "This Item's name is too long";
}
}
string Item::GetItemName()
{
return ItemName;
}
string Item::GetItemDescription()
{
return ItemDescription;
}
With your first concern, which I quote here ....
Room FunStoneRoom = Room();
FunStoneRoom.AddItem(ItemCharcoal);
for (unsigned int VectorPos = 0; VectorPos < FunStoneRoom.GetItemAmount(); VectorPos++)
{
cout << FunStoneRoom.GetItems[VectorPos] << " ";
}
cout << endl;
This gives me an error : Severity Code Description Project File Line Suppression State Error C3867 'Room::GetItems': non-standard syntax; use '&' to create a pointer to member ConsoleApplication25 d:\tiltan\visual studio\ownclasses\room+item+door\consoleapplication25\main.cpp 51
In this case, the cause is a missing () on the call of GetItems. The compiler is treating this as an attempt to get a pointer to the member function Room::GetItems (since similar syntax, when applied to non-member functions, converts the name of a function into a pointer to that function). That is an error, since pointers to member function are not obtained that way.
With your second concern, which I quote here
I also tried:
for (unsigned int VectorPos = 0; VectorPos < FunStoneRoom.GetItemAmount(); VectorPos++)
{
FunStoneRoom.GetItems()[VectorPos];
}
cout << endl;
which doesn't give an error but just prints an empty line.
In this case, the behaviour you see is correct. In the loop, you have removed the cout <<, but are still surprised that it is producing no output. Room::GetItems() does not produce output - it returns a std::vector<Item>. Retrieving an element from a vector, using operator[](), obtains a reference to the corresponding Item, so also does not produce output.
and:
for (unsigned int VectorPos = 0; VectorPos < FunStoneRoom.GetItemAmount(); VectorPos++)
{
cout << FunStoneRoom.GetItems()[VectorPos];
}
cout << endl;
which marks my << with a red line and tells me no operator "<<" matches these > operands...
The code here is the same as the previous lot, except you have re-inserted the cout << in the loop. That causes the compiler to try to find and call an operator<<() function for writing an Item to an output stream. Your code does not declare such a function, so the compiler cannot find it.
You need to create such a function. It needs to be declared in item.h and defined (implemented) in item.cpp. Those files contain no such declarations.
Now we come to your plea for help (which I've already given you).
How do i go about this? I'm really not that advanced and don't know a lot of complicated functions and codes and whatnot so please try to be as simple as u can with me.
I'm going to be blunt. You are the cause of your own problems here.
Firstly, you are not putting enough effort into interpreting what the compiler is trying to tell you. Compilers are ignorant pieces of software but, in their ignorance, they complain fairly consistently about particular types of error. So you need to apply effort into understanding your compiler's error messages. If you don't, you'll never be able to fix your own code when a compiler rejects it.
Then you are compounding your problems by randomly changing code in the hope of fixing it, rather than making reasoned changes. The result of that is either behaviour your don't understand (if the code compiles and runs) or error messages from your compiler that you won't understand, unless you understand the change you actually made.
When you are dealing with a confirmed ignoramus (the compiler) you cannot afford to be ignorant.
A sample example is -
#include <iostream>
using namespace std;
class Item
{
int id;
string description;
public:
Item(int id,string description)
{
this->id=id;
this->description=description;
}
friend ostream& operator<<(ostream& os, const Item& it);
};
ostream& operator<<(ostream& os, const Item& it)
{
os << "Id : " << it.id << " Description : " <<it.description<<endl;
return os;
}
int main()
{
Item it(5, " calculator");
cout << it;
}
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
I would like to start this thread by thanking you for taking to the time to read my query.
I have created a function called retreiveFile which as you would expects retreives a file and reads from it. The text it reads is a set of numbers and text which represent names, cost and that sort of thing.
I have used istringstream to read through the file, determine the starting number(so I know what the line represents(property, card, ect)). Currently I have the file outputting the text but only with its corresponding data.
Example:
9 Oakmoor Road 80 5 0
9 Eldon Road 50 5 0
I need to know how I could pass this information into a class as I assume because I am going to have many objects of the same class I need to pass the data into main somehow.
(I tried creating the class using constructor within the function but it would not work)
I am assuming I would have to create pointers for the information, pass it to main, create the constructors and then delete the pointers.
My question to you would be how could I do this efficiently as I need to create around 30 objects which could fit in several different types of classes as some have different parameters.
I'm sorry in advance in some information seems vague or confusing I am still, in my head, trying to picture how I could do it.
An example of one of the ways I've separated the text within the file so I can easily pass it over to its correct class.
if (word[i].find("1") == 0){ //starts with 1
istringstream is(word[i]);
string aword;
int loopTimes = 0;
while (is >> aword) { // read each word from line
string propertyArray[6];
if (loopTimes == 0){
string stringIdentificationNum = aword;
/* const char * charIdentificationNum = stringIdentificationNum.c_str();
int identificationNum = atoi(charIdentificationNum); */
cout << "(1.1)" << aword;
propertyArray[0] = aword;
}
else if (loopTimes == 1){
cout << "(1.2)" << aword;
propertyArray[1] = aword;
}
else if (loopTimes == 2){
cout << "(1.3)" << aword;
propertyArray[2] = aword;
}
else if (loopTimes == 3){
cout << "(1.4)" << aword;
propertyArray[3] = aword;
}
else if (loopTimes == 4){
cout << "(1.5)" << aword;
propertyArray[4] = aword;
}
else if (loopTimes == 5){
cout << "(1.6)" << aword << endl;
propertyArray[5] = aword;
}
loopTimes++;
/* Property(propertyArray[0], propertyArray[1], propertyArray[2], propertyArray[3], propertyArray[4], propertyArray[5]); */
}
}
An example of the propertyClass
class Property : public Card{
private:
int identificationNum;
string propertyName;
int propertyCost;
int propertyRent;
int propertyColour;
public:
//constructor
Property::Property(int inputIdentificationNum, string inputFName, string inputSName, int inputCost, int inputPropertyRent, int inputPropertyColour){
setIdentificationNum(inputIdentificationNum);
setFirstName(inputFName, inputSName);
setPropertyCost(inputCost);
setPropertyRent(inputPropertyRent);
setPropertyColour(inputPropertyColour);
cout << "Property Created" << endl;
}
//set data
void setIdentificationNum(int inputIdentificationNum){
identificationNum = inputIdentificationNum;
}
void setFirstName(string inputFName, string inputSName){
string nameCombined = inputFName + " " + inputSName;
propertyName = nameCombined;
}
void setPropertyCost(int inputCost){
propertyCost = inputCost;
}
void setPropertyRent(int inputPropertyRent){
propertyRent = inputPropertyRent;
}
void setPropertyColour(int inputPropertyColour){
propertyColour = inputPropertyColour;
}
//retreive data
int getIdentificationNum() {
return identificationNum;
}
string getName(){
return propertyName;
}
int getPropertyCost(){
return propertyCost;
}
int getPropertyRent(){
return propertyRent;
}
int getPropertyColour(){
return propertyColour;
}
};
Thank you in advance for reading this thread.
Passing pointers around is unnecessary for this task and is actually frowned on. An objects data should stay locked up and hidden in the object unless you have a really good reason to expose it. In this case OP doesn't.
What follows cleans up OP's code and fixes some of the problems that made their attempt unworkable and probably lead them down the road to over-complicating things further.
Example is a container for a list of properties. Rather than passing around pointers to to the properties, OP can pass around references to Example and read the properties from example. This allows Example to defend itself from its clients. With a pointer to a property, a client could mistakenly change change a value that could result in breaking Example or another client of Example. With a Getter method, Example can control access to the properties with whatever grain is required.
Example, in this case, allows everyone to see properties, so long as the property exists, but does not allow changing the property.
#include <iostream>
#include <string>
#include <sstream>
#include <stdexcept>
class Example
{
private:
static constexpr size_t MAX_PROPERTIES = 6;
std::string propertyArray[MAX_PROPERTIES];
propertyArray is now a member variable and has scope that matches the object. Consider using a vector. It is not arbitrarily limited in size
public:
Example(std::stringstream & is)
{
std::string aword;
size_t looptimes = 0;
while (is >> aword && looptimes < MAX_PROPERTIES)
{
std::cout << "(1." << looptimes + 1 << ")" << aword << std::endl;
propertyArray[looptimes] = aword;
looptimes++;
This is where making propertyArray a vector really helps. You can use the push_back method to keep adding more and more properties. If you have a case with 8 properties in the future, it uses the exact same code as the 8 property version and you don't have to guard against overflow with the && looptimes < 6 in the while
}
}
std::string getProperty(size_t propertyNo)
New method used to get the properties for clients of Example. That way you don't have to pass around pointers to Example's data. Just pass around Example and if Example wants to give data, it can. No one can use an unprotected back door into Example to screw with Example's data without permission.
{
if (propertyNo < MAX_PROPERTIES)
{
return propertyArray[propertyNo];
}
throw std::out_of_range("Invalid property number");
}
};
And to test it out...
int main()
{
std::stringstream is ("A B C D E F G");
Example test(is);
try
{
std::cout << test.getProperty(4) << std::endl;
std::cout << test.getProperty(6) << std::endl;
}
catch (std::out_of_range & exc)
{
std::cout << exc.what() << std::endl;
}
}
Output:
(1.1)A
(1.2)B
(1.3)C
(1.4)D
(1.5)E
(1.6)F
E
Invalid property number
And now with a std::vector:
#include <iostream>
#include <sstream>
#include <stdexcept>
#include <vector>
class Example
{
private:
std::vector<std::string> propertyArray;
public:
Example(std::stringstream & is)
{
std::string aword;
while (is >> aword)
{
propertyArray.push_back(aword);
std::cout << "(1." << propertyArray.size() << ")" << aword << std::endl;
}
}
std::string getProperty(size_t propertyNo)
{
if (propertyNo < propertyArray.size())
{
return propertyArray[propertyNo];
}
throw std::out_of_range("Invalid property number");
}
};
int main()
{
std::stringstream is ("A B C D E F G");
Example test(is);
try
{
std::cout << test.getProperty(4) << std::endl;
std::cout << test.getProperty(7) << std::endl;
}
catch (std::out_of_range & exc)
{
std::cout << exc.what() << std::endl;
}
}
Output:
(1.1)A
(1.2)B
(1.3)C
(1.4)D
(1.5)E
(1.6)F
(1.7)G
E
Invalid property number
I am making a Poker game in C++, and I am just trying to get started.
I need the ability to compare "Hands", to see which one is greater, equal, or lesser.
So, I have a Hand class now, and I made two other sub-classes that are called Straight and ThreeOfKind (I will add the rest later.
The Hand class has a method called compareTo(Hand* otherHand), it then checks the hand ranking to see which one is better. Also, with the Straights and Three of a Kinds, you can compare them together when they are of the same rank. Like Straights with Straights and Three of a Kinds with Three of a Kinds.
I wrote some initial code today, and my problem is, when I try to call "Hand's" compareTo(Hand* otherHand) method and pass in a Hand, Straight, or Three of a Kind, the compiler complains as it is trying to force me to use the Straight's compareTo(Straight* otherStraight) method. So, I should have overloading, but it's not working.
So in the Straight class after inheritance is done, we should have these two methods:
int Hand::compareTo(Hand* otherHand);
int Straight::compareTo(Straight* otherStraight);
// But, if you do this, it works:
Straight myStraight1 = new Straight(7);
Straight myStraight2 = new Straight(5);
myStraight1.compareTo(myStraight2);
// This is valid...
// If you do this, then the compiler complains!
Straight myStraight3 = new Straight(10);
ThreeOfKind myTrips4 = new ThreeOfKind(3);
myStraight3.compareTo(myTrips4);
// This above line complains that you cannot convert a ThreeOfKind to a Straight
// Even though I am trying to use Hand's compareTo(Hand* otherHand) method and
// cast a Three of a Kind to a Hand object,
// it fails with the overloading!
Here is all the source code...
//////////////////////////
// C++ main header file //
//////////////////////////
#pragma once
class Hand {
private:
int ranking;
public:
Hand(int aRanking);
Hand();
int getRanking();
int compareTo(Hand* otherHand);
};
class Straight : public Hand {
private:
int highCard;
public:
Straight(int aHighCard);
Straight();
int getHighCard();
int compareTo(Straight* otherStraight);
};
class ThreeOfKind : public Hand {
private:
int tripsValue;
public:
ThreeOfKind(int aTripsValue);
ThreeOfKind();
int getTripsValue();
int compareTo(ThreeOfKind* otherThreeOfKind);
};
///////////////////////////
// C++ main .cpp file... //
///////////////////////////
#include <iostream>
#include "PokerTest1.h"
using namespace std;
Hand::Hand(int aRanking) {
this->ranking = aRanking;
}
Hand::Hand() {
this->ranking = 0;
}
int Hand::getRanking() {
return this->ranking;
}
int Hand::compareTo(Hand* otherHand) {
cout << "COMPARING HANDS..." << endl;
if (this->getRanking() < otherHand->getRanking()) {
cout << "HANDS RETURNING -1..." << endl;
return -1;
}
else if (this->getRanking() > otherHand->getRanking()) {
cout << "HANDS RETURNING 1..." << endl;
return 1;
}
cout << "HAND RANKINGS ARE EQUAL..." << endl;
if (this->getRanking() == 4 && otherHand->getRanking() == 4) {
cout << "HANDS ARE BOTH STRAIGHTS..." << endl;
Straight* myStraight1 = (Straight*)this;
Straight* myStraight2 = (Straight*)otherHand;
cout << "COMPARING BOTH STRAIGHTS..." << endl;
return myStraight1->compareTo(myStraight2);
}
else if (this->getRanking() == 3 && otherHand->getRanking() == 3) {
cout << "HANDS ARE BOTH THREE OF A KINDS..." << endl;
ThreeOfKind* myTrips1 = (ThreeOfKind*)this;
ThreeOfKind* myTrips2 = (ThreeOfKind*)otherHand;
cout << "COMPARING BOTH TRIPS..." << endl;
return myTrips1->compareTo(myTrips2);
}
return 0;
}
Straight::Straight(int aHighCard) : Hand(4) {
this->highCard = aHighCard;
}
Straight::Straight() : Hand(4) {
this->highCard = 0;
}
int Straight::getHighCard() {
return this->highCard;
}
int Straight::compareTo(Straight* otherStraight) {
cout << "INSIDE STRAIGHT COMPARE TO..." << endl;
if (this->highCard < otherStraight->highCard) {
cout << "STRAIGHT COMPARE RETURNING -1..." << endl;
return -1;
}
else if (this->highCard > otherStraight->highCard) {
cout << "STRAIGHT COMPARE RETURNING 1..." << endl;
return 1;
}
cout << "STRAIGHT COMPARE RETURNING 0..." << endl;
return 0;
}
ThreeOfKind::ThreeOfKind(int aTripsValue) : Hand(3) {
this->tripsValue = aTripsValue;
}
ThreeOfKind::ThreeOfKind() : Hand(3) {
this->tripsValue = 0;
}
int ThreeOfKind::getTripsValue() {
return this->tripsValue;
}
int ThreeOfKind::compareTo(ThreeOfKind* otherThreeOfKind) {
cout << "INSIDE STRAIGHT COMPARE TO..." << endl;
if (this->tripsValue < otherThreeOfKind->tripsValue) {
cout << "TRIPS COMPARE RETURNING -1..." << endl;
return -1;
}
else if (this->tripsValue > otherThreeOfKind->tripsValue) {
cout << "TRIPS COMPARE RETURNING 1..." << endl;
return 1;
}
cout << "TRIPS COMPARE RETURNIN 0..." << endl;
return 0;
}
int main()
{
// Test the classes...
// with Straight compared to a Three of a Kind.
// Should try to invoke Hand::compareTo(Hand* otherHand) { ... };
// But, instead, it try to invoke Straight::compareTo(Straight* otherStraight) { ... };
// If you put both these methods in the Straight class (rather than using inheritence, it works)
// If you delete Straight::compareTo(Straight* otherStraight) { ... }, the line below compiles
// It is just strange why it won't compile...
Straight* myStraightA = new Straight(9); // Straight of 5, 6, 7, 8, 9
ThreeOfKind* myTripsB = new ThreeOfKind(2); // Three of a Kind of 2, 2, 2
cout << "Compare results..." << endl;
cout << myStraightA->compareTo(myTripsB) << endl; // Compiler error...
return 0;
}
Also, here is a list of the hand rankings:
0 → high card
1 → pair
2 → two pair
3 → three of a kind
4 → straight
5 → flush
6 → full house
7 → quads
8 → straight flush
9 → royal flush
Basically I have a field in the Hand class that stores these rankings as integers. Just so you know.
Lastly, this is the compiler error message:
error C2664: 'int Straight::compareTo(Straight )': cannot convert argument 1 from 'ThreeOfKind' to 'Straight*'
You are trying to overload across classes.
The compiler looks for a compareTo method, finds it in Straight, and doesn't look at Hand. If you add an appropriate using statement, you can tell it to look at Hand's compareTo as well to accomplish your overloading.
class Straight : public Hand {
private:
int highCard;
public:
using Hand::compareTo; // <<< HERE
Straight(int aHighCard);
Straight();
int getHighCard();
int compareTo(Straight* otherStraight);
};
Instead of doing this, I'd recommend you use getRanking() for comparison between hands of different hand types, and define getTieBreaker() overridden by subclasses to handle cases of the same type of hand.
class Hand {
public:
int getRanking();
// virtual causes subclass' version to be called if done from reference or pointer.
virtual int getTieBreaker();
};
This simplifies how Hand compares:
int Hand::compareTo(Hand* otherHand) {
if (this->getRanking() < otherHand->getRanking()) {
return -1;
}
else if (this->getRanking() > otherHand->getRanking()) {
return 1;
}
if (this->getTieBreaker() < otherHand->getTieBreaker()) {
return -1;
}
else if (this->getTieBreaker() > otherHand->getTieBreaker()) {
return 1;
}
return 0;
}
And lets you define it in Straight:
class Straight : public Hand {
//...
public:
int getHighCard();
int getTieBreaker();
};
int Straight::getTieBreaker() {
return this->highCard;
}
I have the following functor:
class ComparatorClass {
public:
bool operator () (SimulatedDiskFile * file_1, SimulatedDiskFile * file_2) {
string file_1_name = file_1->getFileName();
string file_2_name = file_2->getFileName();
cout << file_1_name << " and " << file_2_name << ": ";
if (file_1_name < file_2_name) {
cout << "true" << endl;
return true;
}
else {
cout << "false" << endl;
return false;
}
}
};
It is supposed to be a strict weak ordering, and it's this long (could be one line only) for debug purposes.
I'm using this functor as a comparator functor for a stl::set. Problem being, it only inserts the first element. By adding console output to the comparator function, I learned that it's actually comparing the file name to itself every time.
Other relevant lines are:
typedef set<SimulatedDiskFile *, ComparatorClass> FileSet;
and
// (FileSet files_;) <- SimulatedDisk private class member
void SimulatedDisk::addFile(SimulatedDiskFile * file) {
files_.insert(file);
positions_calculated_ = false;
}
EDIT: the code that calls .addFile() is:
current_request = all_requests.begin();
while (current_request != all_requests.end()) {
SimulatedDiskFile temp_file(current_request->getFileName(), current_request->getResponseSize());
disk.addFile(&temp_file);
current_request++;
}
Where all_requests is a list, and class Request is such that:
class Request {
private:
string file_name_;
int response_code_;
int response_size_;
public:
void setFileName(string file_name);
string getFileName();
void setResponseCode(int response_code);
int getResponseCode();
void setResponseSize(int response_size);
int getResponseSize();
};
I wish I could offer my hypotesis as to what's going on, but I actually have no idea. Thanks in advance for any pointers.
There's nothing wrong with the code you've posted, functionally speaking. Here's a complete test program - I've only filled in the blanks, not changing your code at all.
#include <iostream>
#include <string>
#include <set>
using namespace std;
class SimulatedDiskFile
{
public:
string getFileName() { return name; }
SimulatedDiskFile(const string &n)
: name(n) { }
string name;
};
class ComparatorClass {
public:
bool operator () (SimulatedDiskFile * file_1, SimulatedDiskFile * file_2) {
string file_1_name = file_1->getFileName();
string file_2_name = file_2->getFileName();
cout << file_1_name << " and " << file_2_name << ": ";
if (file_1_name < file_2_name) {
cout << "true" << endl;
return true;
}
else {
cout << "false" << endl;
return false;
}
}
};
typedef set<SimulatedDiskFile *, ComparatorClass> FileSet;
int main()
{
FileSet files;
files.insert(new SimulatedDiskFile("a"));
files.insert(new SimulatedDiskFile("z"));
files.insert(new SimulatedDiskFile("m"));
FileSet::iterator f;
for (f = files.begin(); f != files.end(); f++)
cout << (*f)->name << std::endl;
return 0;
}
I get this output:
z and a: false
a and z: true
z and a: false
m and a: false
m and z: true
z and m: false
a and m: true
m and a: false
a
m
z
Note that the set ends up with all three things stored in it, and your comparison logging shows sensible behaviour.
Edit:
Your bug is in these line:
SimulatedDiskFile temp_file(current_request->getFileName(), current_request->getResponseSize());
disk.addFile(&temp_file);
You're taking the address of a local object. Each time around the loop that object is destroyed and the next object is allocated into exactly the same space. So only the final object still exists at the end of the loop and you've added multiple pointers to that same object. Outside the loop, all bets are off because now none of the objects exist.
Either allocate each SimulatedDiskFile with new (like in my test, but then you'll have to figure out when to delete them), or else don't use pointers at all (far easier if it fits the constraints of your problem).
And here is the problem:
SimulatedDiskFile temp_file(current_request->getFileName(),
current_request->getResponseSize());
disk.addFile(&temp_file);
You are adding a pointer to a variable which is immediately destroyed. You need to dynamically create your SDF objects.
urrent_request = all_requests.begin();
while (current_request != all_requests.end()) {
SimulatedDiskFile temp_file(...blah..blah..); ====> pointer to local variable is inserted
disk.addFile(&temp_file);
current_request++;
}
temp_file would go out of scope the moment next iteration in while loop. You need to change the insert code. Create SimulatedDiskFile objects on heap and push otherwise if the objects are smaller then store by value in set.
Agree with #Earwicker. All looks good. Have you had a look inside all_requests? Maybe all the filenames are the same in there and everything else is working fine? (just thinking out loud here)