Sign in to follow this  
Jaqen

Help with class design issues please? (composition?)

Recommended Posts

I've been writing a wrapper type thing for the console to try to learn a lot and I keep running into hiccups. Right now I have a superclass, Console, that is going to be in charge of everything. It has private members such as handle, char_info buffer, screen width, screen height, mouse, and commands to draw stuff to the screen. Then I was thinking another class such as Widget would inherit Console and this would be to draw different stuff on the screen such as buttons, labels, windows, etc. I was having trouble getting that working and whenever I inherited console and tried to draw stuff with it, nothing would show up... So when trying to research how to do this better I ran across composition and then started thinking I could do something like this (just a little quick pseudo code):
class Console {
    private:
        Mouse *m_cMouse; // Is this even the right syntax, using a pointer like that?
        Widget *m_cWindow1;
        Widget *m_cWindow2;
        Widget *m_cButton1;
    public:
        virtual void OnKeyEvent(const INPUT_RECORD& inputEvent);
        virtual void OnMouseEvent(const INPUT_RECORD& inputEvent);
};

class Mouse {
    private:
        int x;
        int y;
    public:
        void DrawCursor(void);
};

class Widget { // Windows, buttons, labels, etc.
    private:
        int x;
        int y;
    public:
        virtual void OnKeyEvent(const INPUT_RECORD& inputEvent);
        virtual void OnMouseEvent(const INPUT_RECORD& inputEvent);
        
        void Draw(void);
};

Is this how composition works? It's what I got from some articles I read on it. Each class will have it's own event handlers for keyboard/mouse, too. Or is that a bad idea? Or maybe I should stick to trying to get inheritance to work (I guess I do need to work on that concept since I have trouble getting it working right). One big question I've been trying to find a solution to is how to manage different windows. Say I have... Window 1: has 2 buttons, a label Window 2: has a color palette, a button How will I keep track of what should be drawn in each window? I was thinking the console class could have a vector of all the objects such as windows to be drawn to the screen but that's as far as I got. Because I'm still not sure on how to tell what to draw in each window. Should each window have it's own class...? I think that's going a bit far and not needed, especially since I wanted to try to make this code modular so I can use it for any other projects I have using console window. I know this got a little long, but I appreciate anyone who reads this and any help you can give!

Share this post


Link to post
Share on other sites
I'd probably define an interface for a widget, which knows how to accept mouse and keyboard messages and has a pure-virtual method for drawing itself. Then derive individual widget types from it.

Then maintain a list of widgets you can iterate over to draw them. Something like this:


class IWidget
{
// Mouse and keyboard handlers
virtual void OnMouseClick( const MouseParams ¶ms ) {}
virtual void OnKeyPress( const KeyParams ¶ms ) {}

// Pure-virtual Draw() method
virtual void Draw() = 0;
};

// Then derive each widget-type from this, e.g.
class TextBoxWidget
{
// Implement the mouse/key handlers.

void Draw()
{
// However you draw the text box...
}
};

// Then you can draw them somewhere else.
std::list<IWidget*> widgets;
std::list<IWidget*>::iterator itr;
for( itr = widgets.begin(); itr != widgets.end(); ++itr )
itr->Draw();


This can get pretty complicated though, as you'll probably want to keep track of several other things. For example, a z-value, so you know which widgets are on top of which.

You also might want each widget to have a list of 'children', so you can attach widgets to other (e.g. textbox on a window) and have them all move correctly.

Hope this helps.

Share this post


Link to post
Share on other sites
Oy, my projects just keep getting more and more complex and it started out so simple. It helps a lot, and I kinda get what you're saying.

What does setting a virtual function to 0 do, though?

And why a pure virtual method for drawing itself? I guess what I'm asking on this one is what does the word "pure" mean? I know virtual methods are just so methods with the same name can have different functionality but does the word pure add anything to that?

And when you say derive each widget type from the main widget class, what do you mean by that? Inherited or what?

And still, what about inheritance vs composition?

Sorry, my questions being answered is just leading to more questions...


Thanks.

Share this post


Link to post
Share on other sites
Quote:


What does setting a virtual function to 0 do, though?



It makes it 'pure virtual' (or abstract) - allowing you to omit the implementation.

Quote:


I know virtual methods are just so methods with the same name can have different functionality but does the word pure add anything to that?



A virtual method allows subclasses to override or extend the base's implementation. Pure virtual means that the base defines no implementation and is, instead, abstract. A class with any abstract methods cannot be instantiated - it is an abstract class. A class with only abstract methods is considered an interface: the declaration of a contract without any implementation details.

Quote:


And still, what about inheritance vs composition?



Each has its merits, with composition said to be favoured over inheritance. However, if you're creating a traditional GUI hierarchy, you're probably going to have a fair amount of inheritance.

Quote:


And when you say derive each widget type from the main widget class, what do you mean by that? Inherited or what?



'Derived from' is another way of saying 'inherited from'.

Quote:


And why a pure virtual method for drawing itself? I guess what I'm asking on this one is what does the word "pure" mean?



Because a base widget has no visual representation, it would likely not draw itself. Instead, its subclasses (Button, Label, TextBox, etc.) would override the default implementation and draw themselves. You would not be able to instantiate a Widget:



Widget* w = new Widget(); // can't do this, Widget is abstract
Widget* b = new Button(); // *can* do this - but you must use Widget's interface, not Button's...





This second line is fine, but as the comment says, you would have to communicate to the Button 'b' via Widget's interface. Extrapolating that a Button probably adds a string 'text' member to the Widget interface, you would not be able to manipulate this from the Widget interface.

Share this post


Link to post
Share on other sites
Quote:
Original post by zdlr
Quote:


What does setting a virtual function to 0 do, though?



It makes it 'pure virtual' (or abstract) - allowing you to omit the implementation in the base class, and requiring derived classes to provide an implementation in order to be instantiable.
:)

Also, any base class with virtual member functions should, as a rule, also have a virtual destructor (even if it does nothing explicitly - which is often appropriate).

Quote:
Quote:


And still, what about inheritance vs composition?



Each has its merits, with composition said to be favoured over inheritance. However, if you're creating a traditional GUI hierarchy, you're probably going to have a fair amount of inheritance.


Use each for what they're appropriate for. It has been found, in practice, that using inheritance where composition is appropriate is more common than vice-versa, so you often see people stressing the importance of considering composition as an option.




Also, consider that you can also compose by value (sometimes called aggregation) instead of by pointer, if you don't need to share the composed objects between composing objects, and also don't require polymorphic behaviour from them.

Share this post


Link to post
Share on other sites
Thanks, all of this helps a whole lot but also leads to a lot more questions. I don't want to waste anyone's time with all of them, though! I just gotta practice a lot more and get better with classes/pointers it looks like. This stuff may be a tad too advanced for me at the moment so I may just need to take a step back for a bit.

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