0

I'm trying to come up with an abstraction for a game framework and one approach is to create, for example, a graphics and audio class, these are the interfaces used by your games, and you derive specific implementations for your target platforms ( desktop/mobile/console ).

I have some example code of the idea here:

#include <iostream>
#include <string>

using namespace std;

struct Graphics
{
    virtual ~Graphics() {}
    virtual void Rect() {}
};

struct Text
{
    virtual ~Text() {}
    virtual void Print(string s) {}
};

struct IosGraphics : public Graphics
{
    void Rect() { cout << "[]"; }
};

struct IosText : public Text
{
    void Print(string s) { cout << s << endl; }
};

struct Output : public Graphics, public Text
{
};

struct IosOutput : public Output, public IosGraphics, public IosText
{
};

int main() 
{ 
    Output * output = new IosOutput();
    output->Rect(); // this calling Graphics::Rect not IosGraphics::Rect
    output->Print("Hello World!"); // this calling Text::Print not IosText::Print
    cin.get();
}

The problem is that output is using the Text::Print instead of IosText::Print, I wonder if this is related to the diamond problem and I might have to use virtual inheritance or something. Any help is greatly appreciated.

4
  • Make a draw of your class structure and you will see that it doesn't makes sense...somehow... Commented Oct 1, 2012 at 1:11
  • 1
    This is not an answer, and you shouldn't be doing it, and it won't work in a different situation... but: if you make Text and Graphics into virtual bases, you'll get the desired behaviour. Commented Oct 1, 2012 at 1:17
  • 1
    @picarus i.imgur.com/879yA.png ........ Ty you kerrek, it works and my compiler is giving me some cool messages, like ( one class is has dominance over the other! ) Commented Oct 1, 2012 at 1:24
  • @AdamDreaver: Double diamond... but you really have to understand what's going on, because this is almost certainly not the right approach, and it's not going to be extensible. You can easily break this by adding overrides to Output, say. Commented Oct 1, 2012 at 1:30

2 Answers 2

2

"The diamond problem" isn't a problem, it's a symptom of not understanding the distinction between virtual and non-virtual inheritance. In the code above, the class Output has two base classes of type Graphics, one from Output and one from IosGraphics. It also has two base classes of type Text, one from Output and one from IosText. So output->Print("Hello, World!) calls the implementation of Print() in its base, that is, it calls Text::Print(). It doesn't know anything about IosGraphics::Print().

If you change IosGraphics to have Graphics as a virtual base, and change IosText to have Text as a virtual base, and change Output to have Graphics and Text as virtual bases, then things will do what you want because of the Dominance rule. Output doesn't override Rect() but IosGraphics does, so virtual calls to Output->Rect() go to IosGraphics::Rect(), and similarly for Text::Print().

I know, that sounds like magic. The rule is a bit weird, but it works. Try it.

Sign up to request clarification or add additional context in comments.

1 Comment

You're a programming god! TYTY.
2

In general, avoid multiple implementation inheritance at all costs. In your case, IosOutput has two copies of Graphics and Text in it, which is causing the problem.

The best solution is, however, not to use inheritance at all, but instead use membership -- IosOutput has members of type IosGraphics and IosText, and those may legitimately inherit from a more abstract Graphics and Text.

Also, consider interfaces -- classes with only pure virtual methods as an alternative solution.

1 Comment

I don't think your analysis of what's "causing the problem" is correct.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.