2012-10-01 179 views
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 ::打印的,而不是IosText ::打印,我不知道這是關係到鑽石的問題我可能不得不使用虛擬繼承或其他東西。任何幫助是極大的讚賞。

+0

畫出你的班級結構,你會發現它沒有任何意義......不知何故... – Picarus

+1

這不是一個答案,你不應該這樣做,它不會工作在不同的情況下......但是:如果你將'Text'和'Graphics'變成虛擬基地,你會得到想要的行爲。 –

+1

@ picarus http://i.imgur.com/879yA.png ........ 你是kerrek,它的工作原理和我的編譯器給了我一些很酷的信息,比如(一個類是佔優勢的) –

回答

2

「鑽石問題」不是問題,它是不理解虛擬和非虛擬繼承之間區別的症狀。在上面的代碼中,類Output有兩個Graphics類型的基類,一個來自Output,另一個來自IosGraphics。它也有Text類型的兩個基類,OutputIosText的一個。所以output->Print("Hello, World!)在其基地調用執行Print(),即它調用Text::Print()。它不知道任何關於IosGraphics::Print()

如果更改IosGraphicsGraphics虛擬基地,並改變IosTextText虛擬基地,並改變OutputGraphicsText虛擬基地,那麼事情會做什麼你想要的是因爲Dominance規則。 Output不會覆蓋Rect(),但IosGraphics確實如此,所以虛擬調用Output->Rect()轉到IosGraphics::Rect(),並且類似地Text::Print()

我知道,這聽起來很神奇。這條規則有點奇怪,但它有效。嘗試一下。

+0

你是編程上帝! TYTY。 –

2

通常,不惜一切代價避免多次實現繼承。在你的情況下,IosOutput有兩個副本GraphicsText在其中,這是造成這個問題。

最好的解決辦法是,然而,不使用繼承所有,而是使用會員 - IosOutputIosGraphics類型和IosText的成員,以及那些可以合法地從一個更抽象的GraphicsText繼承。

另外,考慮接口 - 只有純虛擬方法的類作爲替代解決方案。

+0

我不認爲你對「導致問題」的分析是正確的。 –