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();
Related
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.
i search for a way to call a method by its string name.
#include <iostream>
#include <string>
class myClass{
public:
void method1(int run){
std::cout << run << std::endl;
}
void method2(int run){
std::cout << run << std::endl;
}
};
int main(){
myClass mc;
std::string call;
call = "method1";
mc.call(1);
call = "method2";
mc.call(2);
}
But the result, is
‘class Myclass’ has no member named ‘call’
I need response "1" and "2";
EDIT :: Very thank's for your help, i get the next solution (i don't know is good for all cases );
#include <iostream>
#include <string>
class myClass{
public:
void method1(int run){
std::cout << "Loaded method => " << run << std::endl;
}
void method2(int run){
std::cout << "Loaded method => " << run << std::endl;
}
void _loadMethods(int method, int params){
switch(method) {
case 1:
method1(params);
break;
case 2:
method2(params);
break;
default:
break;
}
}
};
int main(){
myClass mc;
std::string method;
method = "method2";
if(method == "method1"){
mc._loadMethods(1, 1);
}
if(method == "method2"){
mc._loadMethods(2, 2);
}
}
Thank's
This is not possible in "raw" C++. But... What you are trying to achieve is some kind of Reflection or Class meta-type information.
You can look at this project: http://www.axelmenzel.de/projects/coding/rttr , use Qt: http://doc.qt.io/qt-5/qmetatype.html#details or google for C++ reflection.
I stumbled across this piece of code when I researched for a good example for Observer Design pattern. In main, it gets error, taking address of temporary[-fpermissive] which I dont dont understand what it is frankly. Sending a class refference to an function? Is this real life?
#include <vector>
#include <iostream>
using namespace std;
class AlarmListener
{
public:
virtual void alarm() = 0;
};
class SensorSystem
{
vector < AlarmListener * > listeners;
public:
void attach(AlarmListener *al)
{
listeners.push_back(al);
}
void soundTheAlarm()
{
for (int i = 0; i < listeners.size(); i++)
listeners[i]->alarm();
}
};
class Lighting: public AlarmListener
{
public:
/*virtual*/void alarm()
{
cout << "lights up" << '\n';
}
};
class Gates: public AlarmListener
{
public:
/*virtual*/void alarm()
{
cout << "gates close" << '\n';
}
};
class CheckList
{
virtual void localize()
{
cout << " establish a perimeter" << '\n';
}
virtual void isolate()
{
cout << " isolate the grid" << '\n';
}
virtual void identify()
{
cout << " identify the source" << '\n';
}
public:
void byTheNumbers()
{
// Template Method design pattern
localize();
isolate();
identify();
}
};
// class inheri. // type inheritance
class Surveillance: public CheckList, public AlarmListener
{
/*virtual*/void isolate()
{
cout << " train the cameras" << '\n';
}
public:
/*virtual*/void alarm()
{
cout << "Surveillance - by the numbers:" << '\n';
byTheNumbers();
}
};
int main()
{
SensorSystem ss;
ss.attach(&Gates());
ss.attach(&Lighting());
ss.attach(&Surveillance());
ss.soundTheAlarm();
}
This is ill-formed:
ss.attach(&Gates());
^^^
Gates() is an rvalue (specifically, a prvalue). You cannot take the address of an rvalue. It's not an object that has identity, so it doesn't really have an address that you can take. The language is preventing you from doing something that doesn't make sense to do. If you did store a pointer to this temporary, you'd just end up with a dangling pointer since at the end of this line the temporary Gates would be destroyed.
Since SensorSystem doesn't own its AlarmListeners, you'll have to create them up front:
Gates gates;
Lighting lighting;
Surveillance surveillance;
SensorSystem ss;
ss.attach(&gates);
ss.attach(&lighting);
ss.attach(&surveillance);
This question already has answers here:
How do I use extern to share variables between source files?
(19 answers)
Closed 7 years ago.
I need to use variables I assign in one class into another. For example I have this bit of code. This is CharacterCreation.h followed by CharacterCreation.cpp
#ifndef CHARACTERCREATION_H
#define CHARACTERCREATION_H
class CharacterCreation
{
public:
CharacterCreation();
};
#endif
#ifndef CHARACTERCREATION_H
#define CHARACTERCREATION_H
class CharacterCreation
{
public:
protected:
};
#endif
Here's CharacterCreation.cpp
#include <iostream>
#include "CharacterCreation.h"
#include <string>
CharacterCreation::CharacterCreation()
{
int warrior, mage, rogue, priest;
int class1;
int classID;
std::cout << "Choose a class:\n"
<< "[1] Warrior\n"
<< "[2] Mage\n"
<< "[3] Rogue\n"
<< "[4] Priest\n" << std::endl;
std::cin >> class1;
switch(class1)
{
case 1:
classID=1;
std::cout << "Learned Sword Combat!\n\n";
break;
case 2:
classID=2;
std::cout << "Learned the Arcane Arts!\n\n";
break;
case 3:
classID=3;
std::cout << "Learned the Art of Assasination!\n\n";
break;
case 4:
classID=4;
std::cout << "Learned the Art of the Divine!\n\n";
break;
}
}
And I need to use the class1 variable in main.cpp
#include <iostream>
#include <string>
#include "CharacterCreation.h"
int main()
{
switch(class1)
{
case 1: std::cout << "You chose warrior\n";
case 2: std::cout << "You chose mage\n";
case 3: std::cout << "You chose rogue\n";
case 4: std::cout << "You chose priest\n";
}
}
This code is just an example of what I need, so don't worry about it not working. I just need the method of transferring my variables from CharacterCreation.cpp to main.cpp with them equaling the values I set in CharacterCreation.cpp taught to me.
I'm almost brand new to C++ so if you could ELIF whatever method you teach, that'd be great.
In contrast to the commentors saying there was an "overuse of OOP" - I think that's not the case.
In fact, the code had all the hallmarks of someone new to programming. Case in point:
doing input/output from withing constructors
repetition of code (in general)
repeated switch on "class id" (specificly) <-- this is where the lack of object orientation showed IMO.
Whenever you repeat switch on some kind of type identification, you really want Polymorphic Behaviour. You can model some classes with the different behaviours:
class Character {
public:
virtual std::string name() const = 0;
virtual void acquireSkill() const = 0;
virtual ~Character();
};
class Warrior : public Character {
virtual std::string name() const override;
virtual void acquireSkill() const override;
};
class Mage : public Character {
virtual std::string name() const override;
virtual void acquireSkill() const override;
};
class Rogue : public Character {
virtual std::string name() const override;
virtual void acquireSkill() const override;
};
class Priest : public Character {
virtual std::string name() const override;
virtual void acquireSkill() const override;
};
Now you can just use it as follows:
CharacterCreation factory;
CharacterPtr character = factory.createCharacter(choice);
std::cout << character->name() << "\n";
character->acquireSkill();
The input needs validation. Good input error handling is teh hardz using
C++'s standard library iostreams facilities. See the demo below for some
ideas (which are beyond the scope of my explanations for now though).
The Creation class is likely intended as a kind of factory. So, let's make it so:
using CharacterPtr = std::shared_ptr<Character>;
class CharacterCreation {
public:
enum class Type { none, warrior, mage, rogue, priest };
CharacterPtr createCharacter(Type type);
};
Note that the implementation of createCharacter still does not do the input of the choice!
CharacterPtr CharacterCreation::createCharacter(Type type) {
switch (type) {
case Type::warrior: return std::make_shared<Warrior>();
case Type::mage: return std::make_shared<Mage>();
case Type::rogue: return std::make_shared<Rogue>();
case Type::priest: return std::make_shared<Priest>();
case Type::none: // fall through
break;
}
throw std::range_error("Type"); // character type not implemented?
}
Note: the choice for shared_ptr was a bit arbitrary here. The point is,
for polymorphic object behaviour you need to hold references the the
base-type (implying you typically dynamically allocate the specific
Character subclasses)
Without further ado, the full sample in a single file:
Live On Coliru
#ifndef CHARACTERCREATION_H
#define CHARACTERCREATION_H
#include <memory>
#include <string>
class Character {
public:
virtual std::string name() const = 0;
virtual void acquireSkill() const = 0;
virtual ~Character();
};
class Warrior : public Character {
virtual std::string name() const override;
virtual void acquireSkill() const override;
};
class Mage : public Character {
virtual std::string name() const override;
virtual void acquireSkill() const override;
};
class Rogue : public Character {
virtual std::string name() const override;
virtual void acquireSkill() const override;
};
class Priest : public Character {
virtual std::string name() const override;
virtual void acquireSkill() const override;
};
using CharacterPtr = std::shared_ptr<Character>;
class CharacterCreation {
public:
enum class Type { none, warrior, mage, rogue, priest };
CharacterPtr createCharacter(Type type);
};
#endif
#include <iostream>
//#include "CharacterCreation.hpp"
Character::~Character() { }
CharacterPtr CharacterCreation::createCharacter(Type type) {
switch (type) {
case Type::warrior: return std::make_shared<Warrior>();
case Type::mage: return std::make_shared<Mage>();
case Type::rogue: return std::make_shared<Rogue>();
case Type::priest: return std::make_shared<Priest>();
case Type::none: // fall through
break;
}
throw std::range_error("Type"); // character type not implemented?
}
std::string Warrior::name() const { return "Warrior"; }
std::string Mage::name() const { return "Mage"; }
std::string Rogue::name() const { return "Rogue"; }
std::string Priest::name() const { return "Priest"; }
void Warrior::acquireSkill() const { std::cout << "Learned Sword Combat!\n\n"; }
void Mage::acquireSkill() const { std::cout << "Learned the Arcane Arts!\n\n"; }
void Rogue::acquireSkill() const { std::cout << "Learned the Art of Assasination!\n\n"; }
void Priest::acquireSkill() const { std::cout << "Learned the Art of the Divine!\n\n"; }
//// main.cpp
#include <iostream>
#include <string>
//#include "CharacterCreation.hpp"
namespace {
template <typename T, typename Prompt, typename Validation>
T input(std::istream& is, Prompt prompt, Validation valid)
{
T result;
while (prompt(), !(is >> result) || !valid(result)) {
if (!is && is.eof())
throw std::runtime_error("End of file reading input");
is.clear();
is.ignore(10u << 20, '\n');
}
return result;
}
}
int main() {
auto choice = static_cast<CharacterCreation::Type>(
input<int>(
std::cin,
[] { std::cout << "Choose a character:\n"
<< "[1] Warrior\n"
<< "[2] Mage\n"
<< "[3] Rogue\n"
<< "[4] Priest\n"; },
[](int choice) {
std::cout << "Validation(" << choice << ")\n";
return choice>=1 && choice <=4;
}
)
);
CharacterCreation factory;
CharacterPtr character = factory.createCharacter(choice);
std::cout << character->name() << "\n";
character->acquireSkill();
}
Prints (when inputting '4'):
Choose a character:
[1] Warrior
[2] Mage
[3] Rogue
[4] Priest
Validation(4)
Priest
Learned the Art of the Divine!
CharacterCreation::CharacterCreation()
{
int warrior, mage, rogue, priest;
int class1;
A constructor is very similar to any other kind of function. Just like regular functions, you can declare local variables which are not accessible outside the function. That's what you've done here.
Here's a simplified example of the same problem:
#include <iostream>
void foo() {
int aNumber;
std::cout << "Enter a number! ";
std::cin >> aNumber;
}
int main() {
std::cout << "You entered the number " << aNumber << "\n";
}
Computer programs can be really big and really complex, which makes them really hard to make sure they keep working as new features are added and bugs are fixed. So one of the most critical techniques to avoiding complexity, and to make sure programs are as easy as possible to work on, is to isolate every part of a program as much as possible from other parts of the program, and to tightly control how parts of programs interact with one another.
Languages support this in different ways. One of those ways is the concept of variable scope, or the region of a program that's allowed to interact with a variable. In particular C++ limits the scope of a variable in a function so that nothing outside that function can get at it.
When you do want to have different parts of a program interact, there are many, many ways to do this and it doesn't make much sense to try listing them. Each different method will be suited to different programming goals, so it really depends on what you're doing.
I don't know exactly what your goals are, but having a CharacterCreation class and taking user input in the constructor seems like a dubious design, and it's probably over-complicating things. That said, here's a way to make the program work according to the apparent intent:
// CharacterCreation.h
#ifndef CHARACTERCREATION_H
#define CHARACTERCREATION_H
class CharacterCreation {
int classID;
public:
CharacterCreation();
int getClass();
};
#endif // CHARACTERCREATION_H
// CharacterCreation.cpp
#include "CharacterCreation.h"
#include <cstdlib> // abort()
#include <iostream> // cout, cin, cerr
CharacterCreation::CharacterCreation() {
std::cout << "Choose a class:\n[1] Warrior\n[2] Mage\n"
"[3] Rogue\n[4] Priest\n\n";
std::cin >> classID;
if (std::cin.fail()) {
std::cerr << "Error: failed to get user input.\n";
throw std::runtime_error("input failed");
}
if (classID < 1 || 4 < classID) {
std::cerr << "Error: invalid user input.\n";
throw std::runtime_error("invalid selection");
}
switch (classID) {
case 1:
std::cout << "Learned Sword Combat!\n\n";
break;
case 2:
std::cout << "Learned the Arcane Arts!\n\n";
break;
case 3:
std::cout << "Learned the Art of Assasination!\n\n";
break;
case 4:
std::cout << "Learned the Art of the Divine!\n\n";
break;
default:
abort();
}
}
int CharacterCreation::getClass() { return classID; }
// main.cpp
#include "CharacterCreation.h"
#include <cstdlib> // abort()
#include <iostream> // cout, cin, cerr
int main() {
CharacterCreation cc;
switch (cc.getClass()) {
case 1:
std::cout << "You chose warrior\n";
break;
case 2:
std::cout << "You chose mage\n";
break;
case 3:
std::cout << "You chose rogue\n";
break;
case 4:
std::cout << "You chose priest\n";
break;
default:
abort();
}
}
If I just wanted to write a program with the same output the I might instead write:
// main.cpp
#include <iostream>
#include <array>
struct CharacterClass {
char const *name;
char const *output;
};
int main() {
std::array<CharacterClass, 4> classes = {
{{"Warrior", "Learned Sword Combat!\n\nYou chose warrior"},
{"Mage", "Learned the Arcane Arts!\n\nYou chose mage"},
{"Rogue", "Learned the Art of Assasination!\n\nYou chose rogue"},
{"Priest", "Learned the Art of the Divine!\n\nYou chose priest"}}};
std::cout << "Choose a class:\n";
for (int i = 0; i < classes.size(); ++i) {
std::cout << "[" << i + 1 << "] " << classes[i].name << "\n";
}
int classID;
std::cin >> classID;
if (std::cin.fail()) {
std::cerr << "Error: failed to get user input.\n";
throw std::runtime_error("input failed");
}
if (classID < 1 || classes.size() < classID) {
std::cerr << "Error: invalid user input.\n";
throw std::runtime_error("invalid selection");
}
std::cout << classes[classID - 1].output << '\n';
}
I hope I got the relevant code in here. I have some problem when I want to fetch the menu option that I've added into to menu_1. I have this function on_select(int) that I use to fetch one sub-menu's options, which I do by using the display() function. But when I compile it will say that there are no function named display() in menu_option() class, which is the Base class, but what I want to is to access the display() function which is located in the sub_menu() class.
I have tried multiple thing to get the relevant object from the array without any success, so I'm here now asking for help with this one.
I have this following main()
#include <iostream>
using namespace std;
#include "menu.h"
int main()
{
sub_menu* main_menu = new sub_menu("Warehouse Store Menu");
sub_menu* menu_1 = new sub_menu("Menu1");
main_menu->add_option(new sub_menu("Menu2"));
main_menu->add_option(menu_1);
product_menu->add_option(new add_item("sub_item1"));
product_menu->add_option(new add_item("sub_item2"));
product_menu->add_option(new add_item("sub_item3"));
main_menu->display();
main_menu->on_select(1);
delete main_menu;
return 0;
}
header file
#include <iomanip>
#include <iostream>
#include <string>
using namespace std;
const int MAX_SIZE = 9;
class menu_option
{
public:
menu_option(string const& n) : title(n) {};
virtual ~menu_option();
virtual void on_select(int) = 0;
string get_title() { return title; }
protected:
string title;
};
/* ------------------------------------- */
class sub_menu : public menu_option
{
public:
sub_menu(string const& n)
: menu_option(n) { no_item = 0; }
~sub_menu() { delete[] list; };
void on_select(int);
void add_option(menu_option*);
void display();
private:
menu_option* list[MAX_SIZE]; //container for options in the sub_menu
int no_item;
};
implement file
void sub_menu::on_select(int i)
{
cout << (list[i])->get_title() << endl;
cout << (list[i])->display() << endl; //<------ Doesn't work
}
void sub_menu::add_option(menu_option* item)
{
list[no_item] = item;
no_item++;
}
void sub_menu::display()
{
cout << ">> " << get_title() << " <<"<< endl;
for( int i = 0; i < no_item; i++ )
{
cout << setw(2) << i << ": " << (list[i])->get_title() << endl;
}
}
You can do what you want to do, but it's bad. You have to cast down to sub_menu when you call display() in on_select(). Of course it's not going to work the way you have it, and the compiler is telling you exactly why.
The other option, which is probably better (though without a clear understanding of the problem space may not be the best) would be to add display() as a virtual function to the menu_option class.
To solve your immediate problem you'll want to use dynamic_cast to turn a menu_option* into a sub_menu*, like so:
sub_menu* submenu(dynamic_cast<sub_menu*>(list[i]));
Note that if the cast fails (i.e., the menu_option pointed to by list[i] is not a sub_menu after all) the value of the submenu pointer will be NULL, so make sure you check that it is a valid pointer before using it in subsequent code.