Sign in to follow this  
Drakk

Inherited class function - How would I do this?

Recommended Posts

Drakk    122
Let's say I have a base class called menu, and everytime I want to make a menu, I create a class and inherit from "menu". Like this:
[code]
class Menu
{
void OnCommand( std::string &command );
};

class MyMenu : public Menu
{
void OnCommand( std::string &command );
};

[/code]
Does "Menu" have to exist / created for this to work? What I'm looking todo is to have a many menus derived from "menu" and I want some sort of event system. When a button is "pressed" on a menu, it fires off something to "OnCommand()" and passes something such as "button_pressed". My issue is I would like to handle this all in one function instead of each menu having a think like function and checking if a button was pressed. What would be a way to accomplish this? Should the "Menu" class hold a pointer(s) to all created classes that derive from it, and it'll check if a button was pressed on any of the menus? Sorry if this is confusing, maybe somebody get's my idea. If anybody has worked with HL2. I'm trying a VGUI like system.

Share this post


Link to post
Share on other sites
Texus    248
The code you wrote is already wrong. You can't have a derived class with the same function as the parent class (unless you are working wih virtual functions).

I wouldn't even use classes for this.
I would do something like this (of course other things are possible).
[code]
std::string CurrentMenu ("Main menu");

void OnCommandMainMenu (std::string &command)
{
if (command.c_str == "Button exit")
{
exit(0); //maybe not such a good idea, but this is just an example code.
}
if (command.c_str == "Button SubMenu1")
{
CurrentMenu = "SubMenu1";
}
}

void OnCommandSubMenu1 (std::string &command)
{
if (command.c_str == "Button back")
{
CurrentMenu = "Main menu";
}
}

[/code]
There are of course many other options, but I think you would only make it more dfficult when using derived classes.
It is a long time ago I worked with std::string, so sorry if the code is wrong.

I read the line when my anwer was already written:
[quote]
I would like to handle this all in one function instead of each menu having a think like function and checking if a button was pressed.
[/quote]
But I still think this is an easier way. You can also make one OnCommand function that checks CurrentMenu and then checks command and then does something.
Whatever choice you make, you will always have to write a piece of code for every button.

If you don't like any of my suggested ways there is also the possiblility of linked lists, but that would only make it harder.

Share this post


Link to post
Share on other sites
brx    720
[quote name='Texus' timestamp='1306421796' post='4816062']
The code you wrote is already wrong. You can't have a derived class with the same function as the parent class (unless you are working wih virtual functions).
[/quote]

Actually, that is not entirely correct. You can very well have a method in a derived class with the same name as a method in the parent class even without virtual functinos. However, the outcome is not so nice, as the method in the derived class will only hide the one from the parent class and not really override it (I am assuming we are talking about C++, but the std::string kind of implies that - in other languages like Java all functions are virtual, so it would actually override it).

The following code illustrates that
[code]
#include <iostream>

class Foo {
public:
void DoStuff() { std::cout << "Foo" << std::endl; }
};

class Bar : public Foo {
public:
void DoStuff() { std::cout << "Bar"<<std::endl; }
};

int main() {
Bar *pBar = new Bar();
pBar->DoStuff(); // calls Bar::DoStuff
Foo* pFoo = pBar;
pFoo->DoStuff(); // calls Foo::DoStuff

}
[/code]
In this case the output will be:
Bar
Foo

Same code with making DoStuff virtual:
[code]
#include <iostream>

class Foo {
public:
virtual void DoStuff() { std::cout << "Foo" << std::endl; }
};

class Bar : public Foo {
public:
virtual void DoStuff() { std::cout << "Bar" << std::endl; }
};

int main() {
Bar *pBar = new Bar();
pBar->DoStuff(); // calls Bar::DoStuff
Foo* pFoo = pBar;
pFoo->DoStuff(); // calls Bar::DoStuff through virtual method table

}
[/code]
Will give you the (probably more desireable) output
Bar
Bar


Please note that in the code I posted I have omitted the destructors. If you have virtual functions in your class you should most likely have a virtual destructor which in turn implies that you should also have a copy constructor and a copy assignment operator (google for "C++ rule of three").

Back to your original question: "Does "Menu" have to exist / created for this to work?" Short answer: No (or I do not quite get the question).
Longer: Since objects of your derived class are also objects of the class Menu, it already is created. To me it seems like your Menu class is more like an abstract base class. So in your class that handles your commands you will only need to handle objects of type "Menu" and call their onCommand method. The virtual function will do the rest and call the correct one.

How to manage all your menus is another question. You would need some kind of event system to keep track of activated menus/menu buttons. Maybe you should think about using an GUI toolkit that does all this for you (wxWidgets or Qt comes to mind)?

Share this post


Link to post
Share on other sites
rip-off    10976
Inheritance is for modelling behaviour. Does MyMenu *behave* differently from any other Menu?

For example, consider a menu that consists only of buttons. No matter what the content and the layout is, every menu acts the same - it must provide enough information to draw all the buttons and must be able to provide enough feedback to determine if the user interacts with any button. The real "behaviour" differences lie not in the Menu itself, but in the buttons - or rather in what happens when you click on a button.

Share this post


Link to post
Share on other sites
frob    44908
UI is almost always data driven, not code driven.[font="arial, verdana, tahoma, sans-serif"]
Menus are usually the same regardless of content. A single menu class can generally handle all menu content.

[size="2"]The normal way to handle this is to fill out a data structure describing the menu items, which gets navigated by the menu class.[/size]
[/font]For example, perhaps you'd want something like this:
[source]
struct MenuItem {
std::string label; // Text to display, or look up in your localization system
Functor onSelected; // function to call when the menu item is picked
MenuItem* submenu; // If non-null, when picked the menu class will jump to this one
MenuItem* next; // This menu uses a linked list of items to form an arbitrary menu tree. Use some other structure if you feel the need
eMenuItemState state; // 'normal', disabled, hidden, etc
...
[/source]


The same will be true for all your other UI classes: Rather than having a bunch of unique dialog box classes, use a single class that takes some text strings, callback functions, and a display mode. Rather than having a bunch of unique subclasses to render every list of items, use a single class that takes a collection of objects to display and callbacks for when objects are selected. Etc.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this