I am trying to implement a simple GUI component in C++. The 'Button' class exists in a library that is completely de-coupled from the main program. I want to be able to pass a function-pointer to a button that can be ran upon clicking.
I had some success until I moved the 'button' from being a struct to class for readability and expandability. I reckon that it only worked by pure chance as now I get very random problems.
I basically have something like this:
typedef void(BaseMenu::*ClickAreaCallback)(Button*);
struct Message{
ClickAreaCallback func;
Button* clickArea;
BaseMenu* funObj;
};
The from my classes that subclass BaseMenu, I do something like this:
cb = (ButtonContainer::ClickAreaCallback)&TileSelectorScreen::setTileMode;
and set:
ClickAreaCallback to &cb (as well as funObj)
I then run it upon 'click' by doing:
m->funObj->*m->func)(m->clickArea);
This is obviously wrong as I've read there are problems passing non-static member functions and expecting them to run.
So, is what I am doing impossible? Is what I want possible by using plain C++ without boost or using -std=c++11. I'm limiting myself to the very basics so I can still compile for many platforms.
In short: I want a simple method of calling functions from a class that knows nothing of the class it's calling.
thanks in advance.
In principle there is nothing wrong with pointers to members.
See, e.g., the following code:
#include <iostream>
/** Some API */
struct Button {
virtual void OnClick() = 0;
};
struct BaseMenu {
void f1(Button* b) {
std::cout << "f1(Button*)\n";
b->OnClick();
}
void f2(Button* b) {
std::cout << "f2(Button*)\n";
b->OnClick();
}
void Update() {
}
};
typedef void(BaseMenu::*ClickAreaCallback)(Button*);
struct Message{
ClickAreaCallback func;
Button* clickArea;
BaseMenu* funObj;
};
/** Usage */
class OKButton : public Button {
void OnClick() {
std::cout << "OKButton::OnClick()\n";
}
};
int main(int nArg, char* args[]) {
// Fill message:
BaseMenu menu;
OKButton ok;
Message m1, m2;
m1.func = &BaseMenu::f1;
m1.funObj = &menu;
m1.clickArea = dynamic_cast<Button*>(&ok);
m2.func = &BaseMenu::f2;
m2.funObj = &menu;
m2.clickArea = dynamic_cast<Button*>(&ok);
(m1.funObj ->* m1.func)(m1.clickArea);
(m2.funObj ->* m2.func)(m2.clickArea);
}
But it looks like a conceptional error. You should not need the callback. The buttons should be derived from a base class and have virtual member functions that do the specific stuff.
There follows an example demonstrating the usage of inheritance instead of callbacks.
Note, that ButtonToggle is an example for storing the information inside the button and ButtonNotify is an example for the button notifying the menu.
#include <iostream>
#include <vector>
/** Some API */
struct Button {
double _area[4]; // rectangle x1,y1,x2,y2
Button(std::initializer_list<double> area) {
std::copy(area.begin(),area.begin()+4,_area);
}
virtual void OnClick() = 0;
};
class BaseMenu {
protected:
std::vector<Button*> _buttons;
public:
void Register(Button* btn) {
_buttons.push_back(btn);
}
void OnClick(double pt[2]) {
for(auto iBtn = _buttons.begin(); iBtn!=_buttons.end(); iBtn++) {
if( (*iBtn)->_area[0] <= pt[0] && pt[0] <= (*iBtn)->_area[2]
&& (*iBtn)->_area[1] <= pt[1] && pt[1] <= (*iBtn)->_area[3] ) {
(*iBtn)->OnClick();
}
}
}
};
struct MyMenu : public BaseMenu {
struct ButtonToggle: public Button {
bool _val;
ButtonToggle() :
Button( {0.0,0.0,1.0,1.0} )
{
_val = false;
}
void OnClick()
{
std::cout << "ButtonToggle::OnClick()\n";
_val = not(_val);
}
} buttonToggle;
void DoSomething() {
std::cout << "DoSomething()\n";
}
struct ButtonNotify: public Button {
MyMenu& _myMenu;
ButtonNotify(MyMenu& myMenu) :
Button( {2.0,0.0,3.0,1.0} ),
_myMenu(myMenu)
{}
void OnClick() {
_myMenu.DoSomething();
}
} buttonNotify;
MyMenu() :
buttonNotify(*this)
{
Register(&buttonToggle);
Register(&buttonNotify);
}
};
int main(int nArg, char* args[]) {
MyMenu menu;
double pt[2];
while(( std::cout << "\nCoordinates (end: -1 -1):",
std::cin >> pt[0] >> pt[1],
not( pt[0] == -1.0 and pt[1] == -1.0 ) )) {
menu.OnClick(pt);
}
}
/*
Local Variables:
compile-command: "g++ -g -std=c++11 test1.cc"
End:
*/
Related
I am new to QT started to try out some things with QMap as it seems like a useful tool. I already read some other forum threads but I wasnt able to answer my question. The user is supposed to add and edit different shapes via the GUI. For the shapes I first wrote an abstract base class:
#ifndef BASE_H
#define BASE_H
#include <QListWidget>
#include <QMap>
class Base
{
protected:
QVariantMap m_properties;
QString m_key;
void setKey(const QString& key){
this->m_key=key;
}
public:
Base(){}
virtual ~Base(){}
QString key(){
return m_key;
}
void setProperty(QString key, QVariant variant){
m_properties[key]=variant;
}
virtual void toRTC()=0;
};
#endif // BASE_H
one example of a subclass is an ellipse with the following cpp file:
#include "ellipse.h"
Ellipse::Ellipse(int Start_x, int Start_y, int Rad_x, int Rad_y): rad_x(Rad_x), rad_y(Rad_y), start_x(Start_x), start_y(Start_y)
{
this->setKey("ellipse");
this->setProperty("radX", rad_x);
this->setProperty("radY", rad_y);
this->setProperty("startX", start_x);
this->setProperty("startY", start_y);
}
void Ellipse::set_rad_x(int rad_x)
{
Base::setProperty("radX", rad_x);
}
void Ellipse::set_rad_y(int rad_y)
{
Base::setProperty("radY", rad_y);
}
void Ellipse::set_start_x(int start_x)
{
Base::setProperty("startX", start_x);
}
void Ellipse::set_start_y(int start_y)
{
Base::setProperty("startY", start_y);
}
int Ellipse::get_rad_x()
{
return m_properties["radX"].toInt();
}
int Ellipse::get_rad_y()
{
return m_properties["radY"].toInt();
}
int Ellipse::get_start_x()
{
return m_properties["startX"].toInt();
}
int Ellipse::get_start_y()
{
return m_properties["startY"].toInt();
}
First off, is this a correct approach for the cpp file? I feel my approach is vary laborious.
In my main window file I thought about storing my data in a simple Vector QVector<Base *> data_storage;
Ellipse *e_values = new Ellipse(ui->Ellipse_Value_start_x->value(),ui->Ellipse_Value_start_y->value(), ui->Ellipse_Value_rad_x->value(),ui->Ellipse_Value_rad_y->value());
data_storage.append(e_values);
To load the data, I thought it would be a good idea to use the key to check which object of data_storage I want to load, but I don't really know how I can access the data which is connected to my key.
if(data_storage[t]->key()=="ellipse"){
ui->Ellipse_Value_rad_x->setValue(data_storage[t]->) //how can I access the correct data?
}
I feel like I messed up the entire approach, like how to properly use keys, so how would I do that?
You need to declare all the behaviours you need in the base class. I don't see the need to have Base hold the data.
E.g. if you need to be able to read and write the UI, there should be methods to do that.
class Base
{
public:
virtual ~Base() = default;
virtual void toRTC() = 0;
virtual QVariantMap properties() const = 0;
virtual void writeUI(form_t * ui) const = 0;
virtual void readUI(const form_t * ui) = 0;
};
class Ellipse : public Base
{
int start_x;
int start_y;
int rad_x;
int rad_y;
public:
void toRTC() final { /* ??? */ }
QVariantMap properties() const final {
return { { "radX", rad_x }, { "radY", rad_y },
{ "startX", start_x }, { "startY", start_y } };
}
void writeUI(form_t * ui) const final {
ui->Ellipse_Value_rad_x->setValue(rad_x);
ui->Ellipse_Value_rad_y->setValue(rad_y);
ui->Ellipse_Value_start_x->setValue(start_x);
ui->Ellipse_Value_start_y->setValue(start_y);
}
void readUI(const form_t * ui) final {
rad_x = ui->Ellipse_Value_rad_x->value().toInt();
rad_y = ui->Ellipse_Value_rad_y->value().toInt();
start_x = ui->Ellipse_Value_start_x->value().toInt();
start_y = ui->Ellipse_Value_start_y->value().toInt();
}
};
If you don't want to tie your shapes to the UI, you could define a visitor interface, with a visit method for each shape type.
class ShapeVisitor
{
virtual void accept(Ellipse * ellipse) = 0;
/* virtual void accept(Rectangle * rectangle) = 0; // etc.. */
};
class Base
{
public:
virtual ~Base() = default;
virtual void toRTC() = 0;
virtual QVariantMap properties() const = 0;
virtual void visit(ShapeVisitor & visitor) = 0;
};
class Ellipse : public Base
{
public:
int start_x;
int start_y;
int rad_x;
int rad_y;
void toRTC() final { /* ??? */ }
QVariantMap properties() const final {
return { { "radX", rad_x }, { "radY", rad_y },
{ "startX", start_x }, { "startY", start_y } };
}
void visit(ShapeVisitor & visitor) final {
visitor.accept(this); // calls visitor::accept(Ellipse *)
}
};
class UIReadVisitor : public ShapeVisitor
{
form_t * ui
void accept(Ellipse * ellipse) final {
ellipse->rad_x = ui->Ellipse_Value_rad_x->value().toInt();
ellipse->rad_y = ui->Ellipse_Value_rad_y->value().toInt();
ellipse->start_x = ui->Ellipse_Value_start_x->value().toInt();
ellipse->start_y = ui->Ellipse_Value_start_y->value().toInt();
}
}
class UIWriteVisitor : public ShapeVisitor
{
form_t * ui;
void accept(Ellipse * ellipse) final {
ui->Ellipse_Value_rad_x->setValue(ellipse->rad_x);
ui->Ellipse_Value_rad_y->setValue(ellipse->rad_y);
ui->Ellipse_Value_start_x->setValue(ellipse->start_x);
ui->Ellipse_Value_start_y->setValue(ellipse->start_y);
}
}
I had a class type named reply, its form like this:
class reply {
public:
enum class type {
error = 0,
bulk_string = 1,
simple_string = 2,
null = 3,
integer = 4,
array = 5
};
public:
type get_type(void) const {
return type_;
}
private:
type type_;
};
The reply instance would be returned by other functions, so I would deal with the reply with probing each possible value of the call of get_type. The first solution is to use switch case, but I would like to encapsulate it using 'OOP' thinking as follows:
template<typename Handlers, typename Handlers::type*...types>
class handlers {
private:
static constexpr typename Handlers::type* dealers[] = { types... };
public:
static void deal(const reply& reply) {
dealers[int(reply.get_type())](reply);
}
};
template<typename Handlers>
class handle{
public:
using handles = handlers<Handlers, Handlers::error_handle,
Handlers::bulk_string_handle, Handlers::simple_string_handle,
Handlers::null_handle, Handlers::integer_handle,
Handlers::array_handle>;
};
class handler
{
public:
static void error_handle(const reply&) {
std::cout << "error_handle" << std::endl;
}
static void bulk_string_handle(const reply&) {
std::cout << "bulk_string_handle" << std::endl;
}
static void simple_string_handle(const reply&) {
std::cout << "simple_string_handle" << std::endl;
}
static void null_handle(const reply&) {
std::cout << "null_handle" << std::endl;
}
static void integer_handle(const reply&) {
std::cout << "integer_handle" << std::endl;
}
static void array_handle(const reply&) {
std::cout << "array_handle" << std::endl;
}
public:
using type = decltype(error_handle);
using handles = handle<handler>::handles;
};
Finally, I can deal the reply like this:
int main()
{
reply rep;
handler::handles::deal(rep);
return 0;
}
Note: Each reply has its handler.
What I focus on is whether there is better way to adapt to the solution?
Design at least "central points" as possible. Concentrate on making it easy to add new reply types, the design will flow from that assumption. Create separated parts associated with each reply with a single one central point that choose the handler. The central point is called a factory and small parts implement the same interface.
struct handler {
// I do not know, maybe this should store the reply?
// No idea.
virtual void handle(const reply&);
virtual ~handler();
};
struct error_handler : handler {
void handle(const reply&) { /* blabla */ }
handler construct() { return error_handler(); }
};
/* etc. for each handle type */
// TODO: convert to static array to save dynamic allocatiosn
std::map<std::reply::type, std::function<handler()>> handlers_map{
{ std::reply::error, []() { return error_handler(); } },
/* etc. for each handle type */
};
handler handler_factor(const reply& r) {
return handlers_map.at(r.get_type())();
}
#if YAY_AN_ARRAY // an example of converting map to a static array
// TODO: do it as a member function
static handler error_handler_construct() { return error_handler(); }
static std::array<handler (*)(), 1> handlers_array{
&error_handler_construct,
/* etc. */
};
handler handler_factor(const reply &r) {
// remember about error handling
return handlers_array.at(
static_cast<int>(r.get_type())
)();
}
#elif YAY_ANOTHER_ARRAY
static handler (*const handlers_array[])() = {
[static_cast<int>(reply::type::error)] = &error_handler_construct,
/* etc. */
};
handler handler_factor(const reply &r) {
auto t = static_cast<int>(r.get_type();
if (t < 0 || t > sizeof(handlers_array)/sizeof(*handlers_array)) {
abort();
}
return handlers_array[t]();
}
#enidf
int main() {
reply rep;
auto h = handler_factor(rep);
h.handle(rep);
return 0;
}
I am currently working on a chess engine in C++, and in the engine, I'm trying to modify a string variable "piece" inside of a class "ChessTile" within another class called "ChessBoard".
Anyways when I use a function to return a class, then modify said class, it doesn't change the source variable, and I was wondering how you do that.
Here is a simple script I wrote to demonstrate:
#include <iostream>
#include <string>
class child {
private:
int myVar;
public:
child(int v) {
myVar = v;
}
int getVar() {
return myVar;
}
int setVar(int Svar) {
this->myVar = Svar;
return 0;
}
};
class parent {
public:
child baby = child(0);
child findMyChild(int var) {
if (var == 1) {
return baby;
}
}
};
parent DAD;
int main() {
std::cout << DAD.findMyChild(1).getVar() << std::endl;
DAD.findMyChild(1).setVar(50);
std::cout << DAD.findMyChild(1).getVar() << std::endl;
}
The output for this is:
0
0
But I'm wanting it to be:
0
50
If necessary, I can also post my chess engine. Thank you!
In your code, findMyChild() is returning a copy of the baby ( function returning by value), use return by reference instead like so.
child& parent::findMyChild(int var) {
if (var == 1)
{
return baby;
}
/* other codes */
return baby;
}
You are returning a copy of child in findMyChild. Therefore, you modify only that copy, not the member itself.
You should return a pointer to the member
child* findMyChild(int var) {
return var == 1
? &baby
: nullptr;
}
then dereference it to get/set its value. For example:
DAD.findMyChild(1)->setVar(50);
Since findMyChild can return null pointer in my code you should check its existence before accessing
child* c = DAD.findMyChild(1);
if (c) c->setVar(50);
You can do it via returning pointer/reference of child as stated by another comment or you can do it via an interface in parent class.
#include <iostream>
#include <string>
#define FIRST_CHILD 1
#define CANNOT_FIND_CHILD -1
class child {
private:
int myVar;
public:
child(int v) {
myVar = v;
}
int childGetVar() {
return myVar;
}
int childSetVar(int Svar) {
this->myVar = Svar;
return 0;
}
};
class parent {
public:
child baby = child(0);
int getVar(int var) {
if (var == FIRST_CHILD)
return baby.childGetVar();
return CANNOT_FIND_CHILD;
}
int setVar(int var, int Svar) {
if (var == FIRST_CHILD)
baby.childSetVar(Svar);
return CANNOT_FIND_CHILD;
}
};
parent DAD;
int main() {
std::cout << DAD.getVar(FIRST_CHILD) << std::endl;
DAD.setVar(FIRST_CHILD, 50);
std::cout << DAD.getVar(FIRST_CHILD) << std::endl;
}
I have a class called StateMachine, which controls all possible Entity States.
I then have a class called State which is a base class for unique Entity classes, e.g Attack State, Flee State.
When a new unique State is created (within the StateMachine), it passes in a StateMachine pointer, which will then be stored in the State base class, so that each unique State created can access its State Machine.
When I attempt to access the pointers members (using -> operator) it simple doesn't come up with any public methods, and I don't know why.
If anyone has any clue it would be greatly appreciated.
StateMachine.h
using STATE_PTR = std::shared_ptr<State>;
// Class to implement a finite state machine using the state desing pattern
class StateMachine
{
public:
StateMachine();
~StateMachine();
void OnEnter(STATE_NAME sn);
void OnExit();
void OnEvent(STATE_SYMBOL & ss);
void OnTick(float st);
void ChangeState(STATE_NAME const & sn);
void RegisterState(ENTITY_CLASS const & ec);
typedef std::map<STATE_NAME, STATE_PTR> STATE_REGISTRY;
private:
STATE_REGISTRY state_registry;
STATE_NAME current_state;
};
StateMachine.cpp
using namespace::std;
StateMachine::StateMachine()
: state_registry()
{
current_state = STATE_NAME::UNKNOWN;
}
StateMachine::~StateMachine()
{
state_registry.clear();
}
void StateMachine::OnEnter(STATE_NAME sn)
{
current_state = sn;
if (state_registry[current_state] != nullptr)
{
state_registry[current_state]->OnEnter();
}
}
void StateMachine::OnExit()
{
if (state_registry[current_state] != nullptr)
{
state_registry[current_state]->OnExit();
}
}
void StateMachine::OnTick(float st)
{
}
void StateMachine::OnEvent(STATE_SYMBOL & ss)
{
state_registry[current_state]->OnEvent(ss);
}
void StateMachine::RegisterState(ENTITY_CLASS const & ec)
{
switch (ec)
{
case ENTITY_CLASS::PLAYER_TANK :
state_registry.insert(std::make_pair(STATE_NAME::STATE_1, std::make_shared<PlayerTankState1>(this)));
state_registry.insert(std::make_pair(STATE_NAME::STATE_2, std::make_shared<PlayerTankState2>(this)));
break;
case ENTITY_CLASS::ENEMY_TANK :
state_registry.insert(std::make_pair(STATE_NAME::STATE_3, std::make_shared<EnemyTankState1>(this)));
state_registry.insert(std::make_pair(STATE_NAME::STATE_4, std::make_shared<EnemyTankState2>(this)));
state_registry.insert(std::make_pair(STATE_NAME::STATE_5, std::make_shared<EnemyTankState3>(this)));
break;
default:
break;
}
}
void StateMachine::ChangeState(STATE_NAME const & sn)
{
state_registry[current_state]->OnExit();
current_state = sn;
state_registry[current_state]->OnEnter();
}
State.h
class StateMachine; // Forward decloration of the StateMachine class
// Base class for all states of the game system
class State
{
protected:
State(StateMachine * p)
: mp_Owner(p)
{}
public:
virtual ~State() {}
virtual void OnEnter() = 0;
virtual void OnExit() = 0;
virtual void OnTick(float) = 0;
virtual void OnEvent(STATE_SYMBOL) = 0;
StateMachine * mp_Owner;
};
EnemyTankState.cpp (Unique State)
EnemyTankState1::EnemyTankState1(StateMachine * p)
: State(p)
{
}
EnemyTankState1::~EnemyTankState1()
{
}
void EnemyTankState1::OnEnter()
{
cout << "Hi From Enemy Tank: Partolling State" << endl;
}
void EnemyTankState1::OnExit()
{
cout << "Bye From Enemy Enemy Tank: Partolling State" << endl;
}
void EnemyTankState1::OnTick(float dt)
{
}
void EnemyTankState1::OnEvent(STATE_SYMBOL ss)
{
switch (ss)
{
// Takes Enemy Tank to Attacking State
case STATE_SYMBOL::SYMBOL_2 :
mp_Owner->
break;
}
}
Within the code sample above, the line mp_Owner-> is what is giving me grief, as it is not opening up a list of public methods as you would expect when using a class pointer.
Any help would be much appreciated. Sorry for the long chunks of code, I couldn't think of any other way of getting my problem across.
I have a parent Menu class and children MainMenu, SettingsMenu, PauseMenu, etc.
I want to be able to hold them all in a vector...
I can do
std::vector<Menu*> myVector;
and then typecast each one when I push_back in the vector
pMainMenu = new MainMenu;
myVector.push_back((Menu*)pMainMenu);
and it compiles but something's not working right down the road...
It doesn't have to be a vector but I want to be able to iterate through them.
I'm always trying to implement the Observer pattern and I'm having difficulties with inheritance as well in that area!
For the Observer pattern I have an Observer class and Game inherits Observer. I have a Subject class inherited by InputComponent. Subject has a vector of Observer* called vObserver and a function called addObserver(Observer* observer) and adds the passed pointer in vObserver. I also have a function called Notify(event e), which iterates through vObserver and calls their onNotify functions.
So in Game, I have an InputComponent instance called inputComp. I do inputComp.addObserver(this) and inputComp.vObserver.size() is 1. Good. I have a call to Notify in InputComponent which does get triggered, but when it executes, the vObserver.size inside Subject is 0... idk what I'm doing wrong
EDIT:
class Menu
{
public:
virtual void draw() = 0;
virtual void onMouseMove(int x, int y) = 0;
virtual void onMouseButton(int button, bool is_down) = 0;
friend class InputComponent;
friend class MainMenuInputComponent;
protected:
SDL_Renderer* _renderer;
std::vector<Button> vButton;
std::vector<SDL_Texture *> vTexture;
};
class MainMenu : public Menu
{
public:
MainMenu(SDL_Renderer* renderer);
virtual void draw();
virtual void onMouseMove(int x, int y);
virtual void onMouseButton(int button, bool is_down);
friend class MainMenuInputComponent;
};
class InputComponent: public Subject
{
public:
virtual void processInput()
{}
static bool isMouseWithin(int mouseX, int mouseY, SDL_Rect rect)
{
if (mouseX >= rect.x && mouseX <= rect.x + rect.w && mouseY >= rect.y && mouseY <= rect.y + rect.h)
return true;
else
return false;
}
};
class MainMenuInputComponent : public InputComponent
{
public:
MainMenuInputComponent(MainMenu* owner)
:_owner(owner){}
virtual void processInput();
virtual void onBtnClick(std::string btnName);
MainMenu* _owner;
};
class Game : public Observer
{
public:
Game();
void initSDL();
void initGame();
void processGameInput();
void renderGame();
void update();
virtual void onNotify(Events e);
SDL_Window* myWindow;
SDL_Renderer* myRenderer;
std::vector<MainMenuInputComponent> vInputComponent;
std::stack<MainMenu*> menuStack;
};
Game::Game()
{
initSDL();
initGame();
}
void Game::initGame()
{
//Create the Main Menu
MainMenu* pMainMenu = new MainMenu(myRenderer);
//Add menu to the stack
menuStack.push((pMainMenu));
//Add it's components to respective arrays
MainMenuInputComponent inputComp = MainMenuInputComponent(pMainMenu);
vInputComponent.push_back(inputComp);
//Add Observer/Subject relationship.
inputComp.addObserver((Observer*)this);
int bob = (int)inputComp.vObserver.size(); //to see if size went up
}
void Game::processGameInput()
{
if (!menuStack.empty())
{
for (int i = 0; i < (int)vInputComponent.size(); i++)
{
//Menu* compOwner = (Menu*)(vInputComponent[i]._owner);
//std::unique_ptr<Menu, std::default_delete<Menu>> a = menuStack.top();
if ((vInputComponent[i]._owner) == menuStack.top())
{
vInputComponent[i].processInput();
}
//vInputComponent[i].processInput();
}
}
else
for (int i = 0; i < (int)vInputComponent.size(); i++)
{
vInputComponent[i].processInput();
}
}
void Game::renderGame()
{
SDL_RenderClear(myRenderer);
MainMenu* bob = menuStack.top();
if (!menuStack.empty())
(menuStack.top())->draw();
SDL_RenderPresent(myRenderer);
}
void Game::onNotify(Events event)
{
switch (event)
{
case POP_MENU:
menuStack.pop();
break;
case GOTO_SETTINGS:
//Menu* pSettingsMenu =(Menu*)(new SettingsMenu(myRenderer));
//menuStack.push(std::unique_ptr<Menu>(pSettingsMenu));
break;
// Handle other events, and update heroIsOnBridge_...
}
}
class Subject
{
public:
void addObserver(Observer* observer)
{
vObserver.push_back(observer);
}
void removeObserver(Observer* observer)
{
//vObserver.erase(std::find(vObserver.begin(), vObserver.end(), 8));
}
std::vector<Observer*> vObserver;
protected:
void notify(Events e)
{
for (int i = 0; i < (int)vObserver.size(); i++)
{
vObserver[i]->onNotify(e);
}
}
};
class Observer
{
public:
virtual ~Observer() {}
virtual void onNotify(Events e) = 0;
};
If MainMenu publically inherits from Menu, then you shouldn't even need to type cast the pointer to MainMenu to Menu at all. That is, this should work:
class Menu {};
class MainMenu : public Menu {};
std::vector<Menu*> myVector;
MainMenu* pMainMenu = // ...
myVector.push_back(pMainMenu);
However, what you really should be doing is using something like shared_ptr or unique_ptr. Here's a more complete example, using shared_ptr:
#include <vector>
#include <memory>
#include <iostream>
class Menu
{
public:
virtual void on_event() = 0;
// virtual destructor needed for polymorphic base classes
virtual ~Menu() {}
};
class MainMenu : public Menu
{
public:
virtual void on_event()
{
std::cout << "Hello world! from MainMenu" << std::endl;
}
};
class PauseMenu : public Menu
{
public:
virtual void on_event()
{
std::cout << "Hello world! from PauseMenu" << std::endl;
}
};
class SettingsMenu : public Menu
{
public:
virtual void on_event()
{
std::cout << "Hello world! from SettingsMenu" << std::endl;
}
};
int main()
{
std::vector<std::shared_ptr<Menu>> myVector;
myVector.push_back(std::make_shared<MainMenu>());
myVector.push_back(std::make_shared<PauseMenu>());
myVector.push_back(std::make_shared<SettingsMenu>());
for(auto& menu : myVector) {
menu->on_event();
}
return 0;
}
Expected output:
Hello world! from MainMenu
Hello world! from PauseMenu
Hello world! from SettingsMenu
This should also work and gives you the bonus feature of taking care of memory management for you.