How to execute a class method by string input in C++ - c++

I am trying to develop a text adventure in C++ where users can input string commands (ex. "take apple").
Here is a very naive sample of code I came up with:
# include <iostream>
using namespace std;
class fruit{
public:
string actual_name;
fruit(string name){
actual_name = name;
}
take() {
cout << "You take a " << actual_name << "." << endl;
}
};
fruit returnObjectFromName(string name, fruit Fruits[]){
for(int i = 0; i <= 1; i++){ // to be modified in future depending on Fruits[] in main()
if (Fruits[i].actual_name == name)
return Fruits[i];
}
}
int main(){
string verb;
cout << "Enter verb: ";
cin >> verb;
string object;
cout << "Enter object: ";
cin >> object;
fruit apple("apple");
fruit Fruits[] = { apple }; // to be extended in future
// returnObjectFromName(object, Fruits). ??? ()
}
How can I possibly get the fruit method with something similar to the function returnObjectFromName, if this is even possible?
I began the development with Python (independently), and there I can at least use eval(), but as I understand in C++ this is not an option.
I tried also with map, but I didn't manage to make it work with methods.
Thank you all for your answers.

Its not good way to rely on reflection in C++ and i think there is no way to list methods in classes. Maybe you can use function pointers but pointer to instance methods are hell.
I recommend to use polymorphism and good design. If some items might be taken, then use interface like this:
#include <iostream>
using namespace std;
class ITakeable {
public:
virtual bool isTakeable() = 0;
virtual void take() = 0;
virtual void cannotTake() = 0;
};
class fruit : public ITakeable {
public:
string actual_name;
fruit(string name){
actual_name = name;
}
bool isTakeable() {
return true;
}
void take() {
cout << "You take a " << actual_name << "." << endl;
}
void cannotTake() {
cout << "not needed to be implemented";
}
};
class airplane : public ITakeable {
public:
string actual_name;
airplane(string name){
actual_name = name;
}
bool isTakeable() {
return false;
}
void take() {
cout << "not needed to be implemented";
}
void cannotTake() {
cout << "You CANNOT take a " << actual_name << "." << endl;
}
};
int main() {
fruit apple("apple");
if (apple.isTakeable()) {
apple.take();
}
airplane plane("boeing");
if (plane.isTakeable()) {
plane.take();
} else {
plane.cannotTake();
}
// use of interface in general
ITakeable * something = &apple;
if (something->isTakeable()) {
something->take();
}
something = &plane;
if (something->isTakeable()) {
something->take();
} else {
something->cannotTake();
}
return 0;
}

Since fruit is a user defined type, you have to declare your own methods for your type or you inherit from one previously defined.
There are a lot of method for "built-in" string type
that Performs virtually the same job as eval (...) in python.
Also I noticed your function need not be defined independently outside of class fruit.

Related

Is it possible to use same functions for every class

I have multiple classes and each of them has their own methods. All of these methods perform the same task, as you can see in my code. The only unique thing is the values of the title, code and credit members that are defined inside the classes.
Is there a way to write this code such that a single set of methods can do the required tasks (using the specific values within the class that made the request to the method) for each and every class?
I'm a university student, and due to this I don't want to use inheritance since we haven't learned it yet.
class seng305
{
string title = "Software design and architecture", code = "SENG305";
int credit = 4;
public:
seng305();
~seng305();
string get_info();
string get_title();
int get_credit();
};
class comp219
{
string title = "Electronics in computer engineering", code = "COMP219";
int credit = 4;
public:
comp219();
~comp219();
string get_info();
string get_title();
int get_credit();
};
seng305::seng305()
{
cout << '\t' << "Created" << endl;
}
seng305::~seng305()
{
cout << '\t' << "Destroyed" << endl;
}
string seng305::get_info()
{
return (code + "-" + title);
}
string seng305::get_title()
{
return title;
}
int seng305::get_credit()
{
return credit;
}
//--------------------------------------------------
comp219::comp219()
{
cout << '\t' << "Created" << endl;
}
comp219::~comp219()
{
cout << '\t' << "Destroyed" << endl;
}
string comp219::get_info()
{
return (code + "-" + title);
}
string comp219::get_title()
{
return title;
}
int comp219::get_credit()
{
return credit;
}
As you can see, the get_info(), get_title(), and get_credit() methods do the same thing.
I would like for a single get_info(), get_title(), get_credit() to be able to do the task for each class.
There is no reason to use separate classes at all in this example. A single class will suffice, eg:
class course
{
string title, code;
int credit;
public:
course(const string &title, const string &code, int credit);
~course();
string get_info() const;
string get_title() const;
int get_credit() const;
};
course::course(const string &title, const string &code, int credit)
: title(title), code(code), credit(credit)
{
cout << '\t' << "Created" << endl;
}
course::~course()
{
cout << '\t' << "Destroyed" << endl;
}
string course::get_info() const
{
return (code + "-" + title);
}
string course::get_title() const
{
return title;
}
int course::get_credit() const
{
return credit;
}
Then, you simply create instances of your class as needed, eg:
course seng305("Software design and architecture", "SENG305", 4);
course comp219("Electronics in computer engineering", "COMP219", 4);
...
I know you said that you don't want to use inheritance, but that could be the next logical step, using the above code as a base:
class courseSeng305 : public course
{
public:
courseSeng305() : course("Software design and architecture", "SENG305", 4) {}
};
class courseComp219 : public course
{
public:
courseComp219() : course("Electronics in computer engineering", "COMP219", 4) {}
};
courseSeng305 seng305;
courseComp219 comp219;
...

C++ runtime error with shared_ptr and builder pattern

I was studying c++ language with shared pointer and builder pattern.
I have written following code that is not working but I don't understand why it emits run-time error.
Could you tell me why it is not working well and how can I solve this problem to work well?
#include <iostream>
#include <memory>
#include <string>
using namespace std;
class Popup
{
public:
Popup(int value, string str){
this->v = value;
this->str = str;
}
virtual void print() = 0;
int v;
string str;
};
typedef shared_ptr<Popup> PopupPtr;
class PopupA : public Popup
{
public:
PopupA(int v, string str) : Popup(v, str) { }
virtual void print() {
cout << "PopupA" << endl;
}
};
typedef shared_ptr<PopupA> PopupAPtr;
class PopupB : public Popup
{
public:
PopupB(int v, string str) : Popup(v, str) { }
virtual void print() {
cout << "PopupB" << endl;
}
};
typedef shared_ptr<PopupB> PopupBPtr;
class Builder
{
public:
PopupPtr popupPtr;
Builder() { };
shared_ptr<Builder> init(int value, string str) {
shared_ptr<Builder> builder;
switch (value)
{
case 1:
popupPtr = PopupAPtr(new PopupA(value, str));
break;
case 2:
popupPtr = PopupBPtr(new PopupB(value, str));
break;
default:
cout << "default error" << endl;
break;
}
if (popupPtr) {
builder = shared_ptr<Builder>(this);
}
else {
cout << "popup is null" << endl;
}
if (!builder) {
cout << "builder is null" << endl;
}
return builder;
}
PopupPtr build()
{
if (!popupPtr) {
cout << "popup is null" << endl;
}
return PopupPtr(popupPtr);
}
};
typedef shared_ptr<Builder> BuilderPtr;
int main()
{
BuilderPtr builderPtr = BuilderPtr(new Builder());
PopupPtr popupPtr1 = builderPtr->init(1, "111111111111")->build();
popupPtr1->print();
PopupPtr popupPtr2 = builderPtr->init(2, "222222222222")->build();
popupPtr2->print();
return 0;
}
Thanks in advance for your answers and sorry for my poor english. If you don't understand my question please make a comment.
Your problem is this line:
builder = shared_ptr<Builder>(this);
This will not create a copy of the std::shared_ptr already tracking this, nor will it affect the reference count of it. This creates an entirely new shared pointer which will track this independently, causing a double-delete when both of the reference counts hit zero.
Fortunately, the standard library provides a solution to this problem in the form of std::shared_from_this.
First you need to enable this for your class:
class Builder : std::enable_shared_from_this<Builder>
{
//...
};
Then instead of creating a new std::shared_ptr from this, call std::shared_from_this:
builder = std::shared_from_this();

Polymorphism program

I am needing help with polymorphism. I have no clue how to work with this. I have to write a program that creates an Orc and a Human and demonstrates the behavior of the classes. I am just needing some help with setting this program up. I have set up the classes with the information, but how do I get the createCharacter function to work? Would I have characterTotal = characterStrength + characterDexterity + characterIntelligence in the createCharacter function? I know my program is not correct right now and I have some errors and things, but I am still just trying to get a better understanding of this.
UPDATE:
I am having trouble with the createCharacter function. It is a pure virtual function and I am needing some help on how to get it to work.
For Human class createCharacter will:
Get the values of STR, DEX and INT. Will calculate the total of the values.
(Let’s assume STR = 17, DEX = 12 and INT = 10. It will store 37 into characterTotal.Itwill print out a message: “The strong human Paladin, has a total scoreof 37.” (Strong adjective comes due to STR being 17. If something is above 17 you should say something related. STR = strong, DEX = dexterous, INT =
intelligent).
For Orc class createCharacter will:
Get the values of STR, DEX and INT. Will calculate the total of the values.
However Orcs receive -2 to INT and DEX. They receive +2 to STR. (Let’s
assume STR = 16, DEX = 10 and INT = 8. It will store 16+2,10-2,8-2 = 28 into
characterTotal.
It will print out a message “The berserker Orc has a total score of 28.” (Here the
Orcs get their adjectives from their clan names so you do not need to do
something specific to STR, DEX or INT.)
CODE:
//character.h
#ifndef CHARACTER_H
#define CHARACTER_H
using namespace std;
class Character
{
protected:
float characterTotal;
public:
virtual void createCharacter() = 0; //Pure virtual function
};
#endif
//human.h
#ifndef HUMAN_H
#define HUMAN_H
#include "Character.h"
using namespace std;
class Human
{
private:
int characterStrength;
int characterDexterity;
int characterIntelligence;
string characterType;
public:
Human();//Constructor
int getStength
{
cout << "Enter a number from 0 to 18\n";
cin >> characterStrength;
return characterStrength;
}
int getDexterity
{
cout << "Enter a number from 0 to 18\n";
cin >> characterDexterity;
return CharacterDexterity;
}
int getIntelligence
{
cout << "Enter a number from 0 to 18\n";
cin >> characterIntelligence;
return characterIntelligence;
}
string getType
{
cout << "Please choose one of the following\n";
cout << "A -- Paladin \n";
cout << "B -- Ranger \n";
cout << "C -- Wizard \n";\
cin >> characterType;
return characterType;
}
};
#endif
//orc.h
#ifndef ORC_H
#define ORC_H
#include "Character.h"
#include "Human.h"
using namespace std;
class orc
{
private:
int characterStrength;
int characterDexterity;
int characterIntelligence;
string characterClan;
public:
orc(); //Constructor
int getStrength
{
cout << "Enter a number between 0 to 18\n";
cin >> characterStrength;
return characterStrength;
}
int getDexterity
{
cout << "Enter a number between 0 to 18\n";
cin >> characterDexterity;
return characterDexterity;
}
int getIntelligence
{
cout << "Enter a number between 0 to 18\n";
cin >> characterIntelligence;
return characterIntelligence;
}
string getClan
{
cout << "Please choose one of the following\n";
cout << "A -- Barbarian \n";
cout << "B -- Berserker \n";
cout << "C -- Vanguard \n";\
cin >> characterClan;
return characterClan;
}
};
#endif
Example: A class called Account posesses a container with Character. Your classes Human and Orc inherit both from Character. Inside of your Human class you may want to set spell ABC to all characters which are created (in createCharacter). But if the player creates an Orc, you might want to set another spell XYZ to it, instead of ABC. Base classes come in handy here. In this example you see one of these abstract functions in action (Character::initCharacter).
You can put in more abstract functions inside of Character IF the classes which are supposed to inherit from Character MUST / NEED TO implement these functions.
This is only an example. If you want to do it properly, you need more than this and would have to modify all for database access and further abstraction.
enum CharacterType
{
CHAR_INVALID = 0x0,
CHAR_HUMAN = 0x1,
CHAR_ORC = 0x4
};
class Character
{
public:
Character(unsigned int charGUID) //You might want to set data in the constructor already
: m_charGUID(charGUID) //right after it has been load from Account::LoadAccountInformation()
{
std::cout << "Constructor of \"Character\"" << std::endl;
}
virtual ~Character(void) //Cleanup if needed
{
std::cout << "Destructor of \"Character\"" << std::endl;
}
virtual void createCharacter(void) = 0;
virtual void initCharacter(void) = 0;
CharacterType GetTypeID(void)
{ return m_typeID; }
protected:
void SetTypeID(CharacterType ct)
{ m_typeID = ct; }
private:
Character(const Character &);
unsigned int m_charGUID;
CharacterType m_typeID;
};
class Human : public Character
{
public:
Human(unsigned int charGUID)
: Character(charGUID)
{
SetTypeID(CHAR_HUMAN);
std::cout << "Constructor of \"Human\"" << std::endl;
}
virtual ~Human(void) //Cleanup if needed
{
std::cout << "Destructor of \"Human\"" << std::endl;
}
void createCharacter(void) override
{
//Set data...
}
void initCharacter(void) override
{
std::cout << "You initialized a character of type \"Human\"" << std::endl;
}
};
class Orc : public Character
{
public:
Orc(unsigned int charGUID)
: Character(charGUID)
{
SetTypeID(CHAR_ORC);
std::cout << "Constructor of \"Orc\"" << std::endl;
}
virtual ~Orc(void) //Cleanup if needed
{
std::cout << "Destructor of \"Orc\"" << std::endl;
}
void createCharacter(void) override
{
//Set data...
}
void initCharacter(void) override
{
std::cout << "You initialized a character of type \"Orc\"" << std::endl;
}
};
class Account
{
public:
Account(unsigned int accountGUID)
{ m_accGUID = accountGUID; }
//#Return: False if load from database failed
bool LoadAccountInformation(void) //You could give it data also
{
//You could also load data directly from a database here if you'd like to
//Here are just some sample values (partially hardcoded)
characters.clear();
const int charsOnAccount = 1; //Load from database
for (int i = 0; i < charsOnAccount; ++i)
{
CharacterType ct = CHAR_HUMAN; //Load from database
unsigned int characterGUID = i;
switch (ct)
{
case CHAR_HUMAN:
{
characters[characterGUID] = std::move(std::shared_ptr<Character>(new Human(characterGUID)));
} break;
case CHAR_ORC:
{
characters[characterGUID] = std::move(std::shared_ptr<Character>(new Orc(characterGUID)));
} break;
default:
{
std::cout << "Invalid character type: " << ct << std::endl; //Or log to file
} break;
}
}
return true;
}
void InitCharacters(void)
{
for (auto itr = std::begin(characters); itr != std::end(characters); ++itr)
itr->second->initCharacter();
}
private:
//A unique account-GUID
unsigned int m_accGUID;
//Let's say a unique char-GUID and the Character object
std::map<unsigned int, std::shared_ptr<Character> > characters;
//And more information...
};
int main(int argc, char *argv[])
{
Account ac = Account(1);
ac.LoadAccountInformation();
ac.InitCharacters();
return 0;
}

What is causing this Segmentation Fault: 11?

Okay, so this is effectively the first C++ I have ever written. Consequently, my attempts to research this Segmentation Fault error have failed to yield a useful response that I can understand. Most suggestions say that I'm exceeding the heap memory, but I don't see how I could be in this code. Maybe I'm trying to reference something that I can't reference?
Can someone please take a look at this code and possibly tell me what is causing this error? The code compiles fine, it just throws this error when it runs. I have tried commenting out all the code involving vectors, and that didn't solve the problem. I'm guessing it's something stupid that I'm missing or just a concept about C++ that I don't understand. Either way, some insight would be much appreciated! Thanks in advance.
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
using namespace std;
const int DEFAULT_SIZE = 15;
//---------------------------------User----------------------------------------------------------------------------------
//User Interface Definition
class User
{
public:
User(string nameValue);
string getName();
string getWall();
string getHome();
private:
string name;
};
//User Implementation Definition
User::User(string nameValue) : name(nameValue)
{
}
string User::getName()
{
return name;
}
//---------------------------------Group----------------------------------------------------------------------------------
//Group Interface Definition
class Group
{
public:
Group(string nameValue);
string getName();
void addMember(User newMember);
private:
string name;
vector<User> members;
};
//Group Implementation
Group::Group(string nameValue) : name(nameValue)
{
}
string Group::getName()
{
return name;
}
void Group::addMember(User newMember)
{
members.push_back(newMember);
}
//---------------------------------MessageBuffer----------------------------------------------------------------------------------
//MessgeBuffer Interface Declaration
class MessageBuffer
{
public:
MessageBuffer();
void insert(string user, string recipient, string message);
string readByGroup(string groupName);
string readByUser(string userName);
string readPublic();
private:
string buffer;
};
//MessageBuffer Implementation
MessageBuffer::MessageBuffer() : buffer("")
{
}
void MessageBuffer::insert(string user, string recipient, string message)
{
buffer = "|<" + user + "::" + recipient + ">|" + message + buffer;
}
string MessageBuffer::readByGroup(string groupName)
{
return "Something";
}
string MessageBuffer::readByUser(string userName)
{
return "Something";
}
string MessageBuffer::readPublic()
{
return "Something";
}
//---------------------------------System-------------------------------------------------------------------------------
//System Interface Definition
class System
{
public:
System();
void start();
private:
bool running;
User currentUser;
MessageBuffer messageBuffer;
vector<User> users;
vector<Group> groups;
};
//System Implementation Definition
System::System() : running(false), currentUser(0)
{
}
void System::start()
{
running = true;
string userSelection;
cout << "===========================================================" << endl;
cout << "|\t Welcome to the Auburn Messaging System! \t |" << endl;
cout << "===========================================================" << endl;
while (running) {
cout << "1) Create a new user\n";
cout << "2) Broadcast a message\n";
cout << "3) Multicast a message\n";
cout << "4) Unicast a message\n";
cout << "5) Display Wall page\n";
cout << "6) Display Home page\n";
cout << "7) Create a new group\n";
cout << "8) Join a group\n";
cout << "9) Switch to a different user\n";
cout << "10) Quit Auburn Messaging System\n";
cin >> userSelection;
if (userSelection == "1")
{
running = false;
}
}
}
//----------------------------------------------------------------------------------------------------------------------
int main() {
cout << "Part 1";
System system1;
cout << "Part 2";
system1.start();
cout << "Part 3";
return 0;
}
In the System constructor, currentUser(0) is attempting to initialise a the first parameter of the User constructor (a string) with a literal zero which will be interpreted as a null char pointer.
The std::string constructor (look for basic_string<char> in the debugger) which constructs a string from a char* will be called with a null pointer, which it will dereference and invoke undefined behaviour.

Using type casts to have different objects in a single vector

I am trying to use a paymentList vector which has Cash, Cheque and Credit objects (which are derived classes of Payment) inside of the vector.
I declare the vector like this:
typedef std::vector<Payment*> ListOfPayments;
I add payments like this:
std::cout << "How would you like to pay?" << std::endl;
std::cout << "1. Cash" <<std::endl;
std::cout << "2. Credit"<<std::endl;
std::cout << "3. Cheque"<<std::endl;
std::cin >> choice;
while(choice < 1 || choice > 3)
{
std::cout<<"Please enter a correct number from 1 to 3"<<std::endl;
std::cin >> choice;
}
if(choice == 1)
{
paymentList->push_back(addCash(paymentId,orderId));
}
else if(choice == 2)
{
paymentList->push_back(addCredit(paymentId,orderId));
}
else
{
paymentList->push_back(addCheque(paymentId,orderId));
}
I now want to save this vector to a file. I have started a save function but I'm unsure where to go from here:
void savePayment(ListOfPayments *paymentList)
{
int method;
Cheque * pCheque = dynamic_cast<Cheque *>(paymentList->at(paymentList->size()-1));
Cash * pCash = dynamic_cast<Cash *>(paymentList->at(paymentList->size()-1));
Credit * pCredit = dynamic_cast<Credit *>(paymentList->at(paymentList->size()-1));
std::ofstream* save = new std::ofstream(); // creates a pointer to a new ofstream
save->open("Payments.txt"); //opens a text file called payments.
if (!save->is_open())
{
std::cout<<"The file is not open.";
}
else
{
*save << paymentList->size() << "\n";
ListOfPayments::iterator iter = paymentList->begin();
while(iter != paymentList->end()) //runs to end
{
method = (*iter)->getMethod();
*save << method << "\n";
if(method == 1)
{
pCash->saveCashPayments(save);
}
else if(method == 2)
{
pCredit->saveCreditPayments(save);
}
else
{
pCheque->saveChequePayments(save);
}
iter++;
}
save->close();
delete save;
}
}
It works if I save one type of payment, but as soon as I have two or more payments in the list I get a violation reading location error. I'm guessing it has to do with the type casts being wrong or something? In case I'm wrong here is an example of my save function that runs based on the method variable.
void Cash::saveCashPayments(std::ofstream* save)
{
*save << this->cashTendered << "\n";
*save << this->getId() << "\n";
*save << this->getAmount() << "\n";
*save << this->getOrderId() << "\n";
*save << this->getMethod() << "\n";
}
Any help would be appreciated :)
That is completely wrong approach.
A better approach would be runtime polymorphism. Declare a virtual function called Save in base class and define it in each derived class.
For example, if Payment is the base class, then do this:
class Payment
{
public:
virtual void Save(std::ostream & out) = 0;
};
Then implement Save in all derived classes.
class Cheque : public Payment
{
public:
virtual void Save(std::ostream & out)
{
//implement it
}
};
class Cash : public Payment
{
public:
virtual void Save(std::ostream & out)
{
//implement it
}
};
class Credit : public Payment
{
public:
virtual void Save(std::ostream & out)
{
//implement it
}
};
And then call Save using pointer of Payment* type.
void savePayment(ListOfPayments & payments)
{
std::ofstream file("Payments.txt");
for(ListOfPayments::iterator it = payments.begin(); it != payments.end(); ++it)
{
it->Save(file);
}
}
No need to pass payment by pointer; also don't use new std::ofstream.
Read about Runtime Polymorphism in C++.