多重继承的麻烦

时间:2012-10-01 01:01:33

标签: c++ oop

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

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

#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,我想知道这是否与钻石问题有关,我可能不得不使用虚拟继承等。非常感谢任何帮助。

2 个答案:

答案 0 :(得分:2)

通常,不惜一切代价避免多次实现继承。在您的情况下,IosOutput中有GraphicsText两个副本,这会导致问题。

但是,最好的解决方案是根本不使用继承,而是使用成员身份 - IosOutput具有IosGraphicsIosText类型的成员,并且这些成员可以合法地继承更抽象的GraphicsText

另外,请考虑接口 - 仅使用纯虚方法的类作为替代解决方案。

答案 1 :(得分:2)

“钻石问题”不是问题,它是不理解虚拟和非虚拟继承之间区别的症状。在上面的代码中,类Output有两个类型为Graphics的基类,一个来自Output,另一个来自IosGraphics。它还有两个类型为Text的基类,一个来自Output,另一个来自IosText。因此,output->Print("Hello, World!)会在其基础中调用Print()的实现,即调用Text::Print()。它对IosGraphics::Print()没有任何了解。

如果您将IosGraphics更改为Graphics作为虚拟基础,并将IosText更改为Text作为虚拟基础,并将Output更改为GraphicsText作为虚拟基础,然后由于,事情会做你想做的事情优势规则。 Output不会覆盖Rect()IosGraphics会覆盖Output->Rect(),因此IosGraphics::Rect()的虚拟呼叫转移到Text::Print(),{{1}}也是如此。

我知道,这听起来像魔术。规则有点奇怪,但它有效。试试吧。