0

私はゲーム フレームワークの抽象化を考え出そうとしています。1 つのアプローチは、たとえば、グラフィックスとオーディオ クラスを作成することです。これらはゲームで使用されるインターフェイスであり、ターゲット プラットフォーム用の特定の実装を派生させます (デスクトップ/モバイル/コンソール)。

ここにアイデアのサンプルコードがあります:

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

問題は、出力が IosText::Print の代わりに Text::Print を使用していることです。これはひし形の問題に関連しているのでしょうか。仮想継承などを使用する必要があるかもしれません。どんな助けでも大歓迎です。

4

2 に答える 2

2

「菱形継承問題」は問題ではなく、仮想継承と非仮想継承の違いを理解していないことの兆候です。上記のコードでは、クラスOutputにはタイプの2つの基本クラスがありますGraphics。1つはfromOutputで、もう1つはfromIosGraphicsです。また、タイプの2つの基本クラスがありますText。1つはfromOutputで、もう1つはfromIosTextです。したがって、そのベースでoutput->Print("Hello, World!)の実装を呼び出します。つまり、を呼び出します。については何も知りません。Print()Text::Print()IosGraphics::Print()

仮想ベースとして持つように変更し、仮想ベースとしてIosGraphics持つよう変更し、仮想ベースとして持つように変更した場合、ドミナンスルールにより、物事は希望どおりに機能しますオーバーライドしませんが、オーバーライドします。そのため、に移動する仮想呼び出し、および同様に。GraphicsIosTextTextOutputGraphicsTextOutputRect()IosGraphicsOutput->Rect()IosGraphics::Rect()Text::Print()

私は知っています、それは魔法のように聞こえます。ルールは少し奇妙ですが、機能します。それを試してみてください。

于 2012-10-01T01:18:45.397 に答える
2

一般に、複数の実装の継承は何としても避けてください。あなたの場合、問題の原因となっているandIosOutputの 2 つのコピーがあります。GraphicsText

ただし、最良の解決策は、継承をまったく使用せず、代わりにメンバーシップを使用することIosOutputです。タイプIosGraphicsandのメンバーがありIosText、それらはより抽象的なGraphicsandから正当に継承できTextます。

また、インターフェイス (代替ソリューションとして純粋な仮想メソッドのみを持つクラス) も検討してください。

于 2012-10-01T01:09:05.693 に答える