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.
“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
Outputhas two base classes of typeGraphics, one fromOutputand one fromIosGraphics. It also has two base classes of typeText, one fromOutputand one fromIosText. Sooutput->Print("Hello, World!)calls the implementation ofPrint()in its base, that is, it callsText::Print(). It doesn’t know anything aboutIosGraphics::Print().If you change
IosGraphicsto haveGraphicsas a virtual base, and changeIosTextto haveTextas a virtual base, and changeOutputto haveGraphicsandTextas virtual bases, then things will do what you want because of the Dominance rule.Outputdoesn’t overrideRect()butIosGraphicsdoes, so virtual calls toOutput->Rect()go toIosGraphics::Rect(), and similarly forText::Print().I know, that sounds like magic. The rule is a bit weird, but it works. Try it.