Reputation: 7691
I'm trying to achieve polymorphism by having types of Event subtypes inherit from the base class Event
. The idea is that there is always an active event, denoted by the pointer in Runner (Event* current_event
). When the Runner::step
method is called, the Event::go
method is called, which flips some switches and changes the current behaviour of the program. Then, the pointer is pointed at a different event until Runner::step
is called again.
The issue is that the pointer is always using the base class Event
versions of variables. It might be a simple fix but I'd be greatful if somebody could point it out to me.
#include <iostream>
using namespace std;
struct Flags {
public:
bool withCheese = false;
bool withBiscuits = false;
};
class Event {
std::string description = "The base class";
public:
std::string id = "Base";
Event() = default;
~Event() = default;
Event(Event const &event) = default;
Event &operator=(Event &&) = default;
virtual void go(Flags &flags) {};
virtual void printDescription() {
std::cout << description << std::endl;
}
};
class EatCheese : public Event {
std::string description = "We eat cheese now";
public:
using Event::Event;
std::string id = "EatCheese";
void go(Flags &flags) override {
flags.withCheese = true;
flags.withBiscuits = false;
};
};
class EatBiscuits : public Event {
std::string description = "We eat biscuits now";
public:
using Event::Event;
std::string id = "EatBiscuits";
void go(Flags &flags) override {
flags.withCheese = false;
flags.withBiscuits = true;
};
};
class Runner {
public:
EatCheese eventA;
EatBiscuits eventB;
Event *current_event = &eventA; // The problematic line: this still points to Base, not eventA.
Flags flags;
Event* step() {
cout << "description: ";
current_event->printDescription();
current_event->go(flags);
if (current_event->id == "EatCheese") {
cout << "We have EatCheese"<<endl;
current_event = &eventB;
}
else if (current_event->id == "EatBiscuits") {
cout << "We have EatBiscuits"<<endl;
current_event = &eventA;
}
cout << endl;
return current_event;
}
};
int main() {
Runner runner;
cout << "current_event_id: " << runner.current_event->id << ", with biscuits: " << runner.flags.withBiscuits << ", with Cheese: " << runner.flags.withCheese << endl;
runner.step();
cout << "current_event_id: " << runner.current_event->id<< ", with biscuits: " << runner.flags.withBiscuits << ", with Cheese: " << runner.flags.withCheese << endl;
runner.step();
cout << "current_event_id: " << runner.current_event->id<< ", with biscuits: " << runner.flags.withBiscuits << ", with Cheese: " << runner.flags.withCheese << endl;
return 0;
};
This will output
current_event_id: Base, with biscuits: 0, with Cheese: 0
description: The base class
current_event_id: Base, with biscuits: 0, with Cheese: 1
description: The base class
current_event_id: Base, with biscuits: 0, with Cheese: 1
Where I expect it to output:
current_event_id: EatCheese, with biscuits: 0, with Cheese: 1
description: We eat cheese now
current_event_id: EatBiscuits, with biscuits: 1, with Cheese: 0
description: We eat biscuits now
current_event_id: EatCheese, with biscuits: 1, with Cheese: 0```
Upvotes: 0
Views: 69
Reputation: 9835
You are referring to non-virtual members in your main function.
struct Base { int myNumber = 0; };
struct Child : Base { int myNumber = 10 };
both classes have a myNumber
member but since Child
is a derviative of Base
it has actually 2 myNumber
of which the one from the base class is hidden.
If you do
Child obj;
std::cout << obj.myNumber;
it would print 10, because your expression refers to Child::myNumber
. However, if you make it a pointer or reference of your base class
Child obj;
Base* ptr = &obj;
Base& ref = obj;
std::cout << ptr->myNumber << ref.myNumber;
both will print 0 because the object is now treated as type Base
. The member variable in question usually hides the base member, but since our variable has a different type now, the access path to that variable is different aswell and Base::myNumber
is the symbol we're referring to now.
So create virtual getter functions:
class Event {
std::string description = "The base class";
public:
std::string id = "Base";
virtual std::string const& getDescription() const;
virtual std::string const& getId() const;
// ...
};
and override them in your child class.
Also, for further reading I recommend: Why does an overridden function in the derived class hide other overloads of the base class?
Upvotes: 1