Skip to main content
GameDev.net gamedev.net
🔒 Locked

Multiple base classes design

Started by Texus Jun 11, 2013 at 9:42 AM 5 replies 2.1k views
Original Post
Texus
Texus
I was trying to port my c++ gui to c# when I hit this issue.
On one place I inherit from two base classes, which is apparently not possible in c#.
Can anyone help me by suggesting a different design to work around this problem?

Here are some more details:
I have an Object class from which every widget inherits from.
Then there is the Group class which is a container and has a list of objects.
And then there is GroupObject. This is where the problem lies because it inherits from both Object and Group. It is used by classes like ChildWindow. These classes need to be drawable (the window treats child windows just like any other object) and they need to be containers (the child window will draw the widgets inside it, the window doesn't know and doesn't need to know what the child window contains).

I cannot make Group an extension on Object, because the Window is a Group and not an Object (this is the only Group which isn't an Object). And the window has to inherit from Group because every Object has a pointer to its parent which can be either a GroupObject or the Window (so a Group pointer).

Does anyone has a suggestion on how to change my design to make this work?
If you need more information or if I wasn't clear enough about something, just ask.

Thanks in advance
TGUI, a C++ GUI for SFML
texus.me
Andy474
Andy474

Interfaces.

Your Object could be an Interface


public interface IObject
{
   //Methods and Variables
}

I wouldn't have any functionality in the object myself, I'd have that higher up in the chain and have only the Object be a 'Contract' ... or a promise that an Object will have these fields / variables.

Hard to say anything else without code. you're going to need either interfaces, or redesign classes.

Personally I have something like this:

- IRenderable interface : contains Draw(), Update(), and Init() functions (i also use this in many other places, so its not as useless as it seems :P)

- GUIComponent - base class of ALL GUI stuff (implements IRenderable)

Then I have

- GUIContainer : (like a Panel, inherits GUIComponent)

- GUIControl : (anything control inherits from this, handles clicking logic, inherits from GUIComponent)

Then I hasve classes like:

- Panel : GUIContainer

- Button : GUIComponent

- Image : GUIComponent

etc. etc.

Andy474
Andy474

I cannot make Group an extension on Object, because the Window is a Group and not an Object (this is the only Group which isn't an Object). And the window has to inherit from Group because every Object has a pointer to its parent which can be either a GroupObject or the Window (so a Group pointer).

I just re-read this: why not make Group an interface?


public interface IGroup<T>
{
    T Parent {get; set;}
}

(may or may not be able to use the magic T)

Texus
Texus
Thanks for the fast responce.

I already thought I would have to do something with interfaces.

Making an object an interface won't be that easy though. It inherits from a class that comes from another library, so I would first have to break this inheritance. It's not that bad, but that would require some extra work. Also there is quite some code in Object itself which I don't want to write in every object seperately.

The only problem I see with your idea from the first post is that Window isn't a GUIComponent but has to be like GUIContainer.
GUIComponent has a 'pointer' to GUIContainer which could be either a panel or the window, and that's where the problem lies.

Group could be made an interface, but then I would have a lot of code duplication: everything that is now in Group should be implemented inside GroupObject and Window in the same way. I could agree that Group could be the contract and that the others have to implement its functions, but the reason that I placed code in Group is because these functions would be implemented in exactly the same way in both GroupObject and Window.

So if I live with a bit of code duplication then I can solve this, but I'm still looking for another way.
TGUI, a C++ GUI for SFML
texus.me
TheAngryPlatypus
TheAngryPlatypus

Hello Texus.

After a short look in your TGUI code, I think the problem is the Window class.

First: the naming is confusing. In a GUI I expect a window to be a widget. In your case Window is a renderer and should act like a root for your widgets as well. (Thats why it inherits from Group but not from Object)

My idea: I would get rid of the Group class and put all its code into GroupObject. Then let window contain a GroupObject named root. (or inherit a RootObject or Desktop etc. from GroupObject)

Texus
Texus
Thanks for taking the time to look into this.

The name might indeed be confusing, which is why in the latest version I changed it to a Gui class which differs slightly from the current Window class. But I hadn't thought yet about having a Group inside the window/gui instead of inheriting from it.

For the c++ version that is going to give complications as the whole callback system is build around these groups. Objects send their callback to their parent until it reaches the window. So if window wouldn't be a group, but would just contain a GroupObject then the callback would end up at that GroupObject, which has no idea on how to communicate with the window itself to alert the user of the callback. I don't want to go change the whole design again now to fix this, that might be for later. But I can always keep the c++ version in the way it is now and only make the change in the c# version.

I'm not far enough in the c# version to find out whether there are going to be complications too (I can't think of any at the moment), but as the callback will be handled in a completely different way, I might actually be able to do it that way.
TGUI, a C++ GUI for SFML
texus.me
Texus
Texus
Actually this doesn't immediately solve it.
I would still have to put all functions from Group into the Window class and let these functions call those from the 'Desktop' object.
Because without letting Window inherit from Group, it won't have Add, Remove, Copy, GlobalFont and stuff like that. These are things that every group should have, so these functions must end up being be public in both GroupObject and Window.

And making the window a widget would give it some functions that aren't really usefull. As a root object, you can't have siblings thus functions like MoveToBack and MoveToFront don't make much sense. And those aren't the only functions from Object that wouldn't mean much.
TGUI, a C++ GUI for SFML
texus.me

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.