0

我正在尝试为游戏框架提出一个抽象,一种方法是创建,例如,图形和音频类,这些是游戏使用的接口,并且您为目标平台派生特定实现(桌面/移动/控制台)。

我在这里有一些想法的示例代码:

#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();
}

问题是输出使用的是 Text::Print 而不是 IosText::Print,我想知道这是否与菱形问题有关,我可能不得不使用虚拟继承或其他东西。任何帮助是极大的赞赏。

4

2 回答 2

2

一般来说,不惜一切代价避免多重实现继承。在您的情况下,其中IosOutput有两个副本GraphicsText这是导致问题的原因。

然而,最好的解决方案是根本不使用继承,而是使用成员资格——IosOutput具有 and 类型的成员IosGraphicsIosText并且这些成员可以合法地从更抽象的Graphicsand继承Text

另外,考虑接口——只有纯虚方法的类作为替代解决方案。

于 2012-10-01T01:09:05.693 回答
2

“钻石问题”不是问题,它是不了解虚拟继承和非虚拟继承之间区别的症状。在上面的代码中,该类Output有两个 type 的基类Graphics,一个 fromOutput和一个 from IosGraphics。它还有两个类型的基类Text,一个 fromOutput和一个 from IosText。所以在它的基类中output->Print("Hello, World!)调用了实现Print(),也就是说,它调用了Text::Print(). 它对IosGraphics::Print().

如果您更改IosGraphics为拥有Graphics作为虚拟基地,并更改IosText为拥有Text作为虚拟基地,并更改Output为拥有GraphicsText作为虚拟基地,那么由于优势规则,事情会按照您的意愿行事。Output不会覆盖Rect()IosGraphics会覆盖,因此虚拟调用Output->Rect()go toIosGraphics::Rect()和类似 for Text::Print()

我知道,这听起来很神奇。这个规则有点奇怪,但它确实有效。尝试一下。

于 2012-10-01T01:18:45.397 回答