1

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;
};
user1420563
  • 195
  • 1
  • 12
  • 1
    Are you a victim of [sliced objects](http://stackoverflow.com/questions/274626/what-is-the-slicing-problem-in-c)? – πάντα ῥεῖ Sep 21 '14 at 19:34
  • yes something like that... and when I did std::vector it worked but that's stupid because I wont have more than one MainMenu...! what to do? – user1420563 Sep 21 '14 at 19:48
  • 1
    _@user1420563_ Please don't try to improve your post with additional comments. Just place a horizontal bar and add this information to your question. – πάντα ῥεῖ Sep 21 '14 at 20:01
  • @user1420563: I'm sorry, but you need to create [a minimal, complete, and verifiable example](http://stackoverflow.com/help/mcve) of your problem. It's a very good thing that you have provided code snippets, but as written they will not even compile, so I can't observe the behavior you see. If you want to others to help, you need to narrow down your problem to a few hundred lines at the most. – In silico Sep 21 '14 at 20:12
  • Ok I'm working on it, trying not to put too much code but their all related – user1420563 Sep 21 '14 at 20:16
  • anything new? I'm still stuck I don't know what else to try – user1420563 Sep 21 '14 at 23:51

1 Answers1

1

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.

In silico
  • 51,091
  • 10
  • 150
  • 143
  • I was using unique_ptr, and in fact the different Menus are in a stack, but for some reason when I did myStack.top()->functionCall() it gave me a wierd memory error. I tried to se what exactly was myStack.top(), so I created a varible and assigned it to that variable so that I can look at it's value in the debugger, but it said something along the lines that I was trying to access a deleted function or something. So I just used normal pointers and it got rid of that – user1420563 Sep 21 '14 at 19:42
  • @user1420563: If your `Menu`s are on the stack, then why did you have `pMainMenu = new MainMenu;` in your question? Can you update your question to reflect what you actually have? By default, `shared_ptr` and `unique_ptr` will handle your pointers as though they point to dynamic storage, not to stack objects, which might explain why you're seeing errors. – In silico Sep 21 '14 at 19:51
  • ok I my code I hope that'll be enough let me know if you want more – user1420563 Sep 21 '14 at 21:12