3

この問題を正しく説明できるといいのですが、少し混乱します。

flixel に似たゲーム ライブラリに取り組んできましたが、Flash の代わりに C# の XNA フレームワークを使用しています。現在のクラス構成はこんな感じです。

ClxBasic -> ClxObject -> ClxSprite

各クラスにはコンストラクターがあり、その下のクラスのコンストラクターを呼び出します。これを行うには、このコードを使用します。

namespace Test
{
    public class ClxBasic
    {
        public ClxBasic()
        {
            Constructor();
        }

        public void Constructor()
        {
            DoSomething();
        }
    }

    public class ClxObject : ClxBasic
    {
        public ClxObject() : base()
        {
            Constructor();
        }
            public void Constructor()
            {
                    DoSomething();
            }
    }

    public class ClxSprite : ClxObject
    {
        public ClxSprite() : base()
        {
            Constructor();
        }
            public void Constructor()
            {
                    DoSomething();
            }
    }
}

基本的に、新しい ClxSprite を作成すると、ClxSprite コンストラクターが呼び出され、その下にあるすべてのコンストラクター (ClxObject および ClxBasic) が呼び出されます。

これを行うためのより簡単な方法があると確信しており、私はすべて耳を傾けています。

ただし、私のより大きな問題は、実際には他のクラスからメソッドを適切に派生させてオーバーライドする方法です。

問題は、ClxSprite から拡張されたクラスを作成する場合、たとえば、最も基本的なクラス (ClxBasic) からオーバーライドされたメソッドを呼び出す場合、一番上のメソッドではなく一番下のメソッドのみを呼び出すことです。

これを行う必要がある理由は、ClxBasic コンストラクターのリストに自分自身を追加することによって ClxBasic から派生したすべてのオブジェクトを制御するグローバル クラスがあるためです。

コード例を次に示します。

namespace Test
{
    public static class ClxG()
    {
        public static List<ClxBasic> GlobalObjects; //All objects will be added here by the ClxBasic constructor
            ClxSprite test = new ClxSprite();
            GlobalObjects.Add(test);
        public static Update()
        {
            foreach(ClxBasic basic in GlobalObjects)
                basic.Update(); //Calling this calls ClxBasic.Update() when it should call ClxSprite.Update()
        }
    }
}

basic.Update() を呼び出すと、オブジェクトが ClxObject または ClxSprite またはその他の派生クラスであるにもかかわらず、ClxBasic にある一番下の Update に移動します。

foreach ループで ClxBasic を ClxSprite に変更することで、そのクラスのコンストラクター メソッドを適切に呼び出すことができます。ただし、メソッドをオーバーライドするライブラリに基づいてカスタム クラスを作成する場合は、下位の Update が呼び出されます。

ただし、特に計画していないクラスを追加することはできません。たとえば、ClxSprite からクラス Player を派生させ、Update() メソッドをオーバーライドする場合、GlobalObjects リストに追加されますが、更新が呼び出されることはなく、最高になるのは ClxSprite です。

私がそれを機能させたい方法は、Game1.cs で、FlxG.Update() を Game.Update() ループに入れ、オブジェクトを作成し、フレームワークが残りを処理できるようにすることです。

全体がある種の継承の開始のように感じ、ある種の脳を傷つけます。

4

3 に答える 3

1

子クラスの実装の一部として基底クラスのメソッドも呼び出すには、次のようにします。

class Base {
  public virtual void Method() {
    // ...
  }
}

class Derived : Base {
  public override void Method() {
    base.Method();
    // ....
  }
}

class Derived2 : Derived {
  public override void Method() {
    base.Method();
    // ....
  }
}

ただし、子メソッドは基本メソッドを呼び出す必要はありません。

一方、コンストラクターは常に (最終的に) 基本コンストラクターを呼び出す必要があります。

ここで、基本クラス メソッドを何らかの処理の一部として常に呼び出す必要がある場合は、テンプレート メソッド patternを使用できます。基本的に、基本クラスには、仮想 (または抽象) メソッドを呼び出すアルゴリズムを駆動する非仮想メソッドがあります。子クラスがオーバーライドして、独自のバージョンを作成できます。

于 2012-06-23T12:39:03.427 に答える
1

base()基本クラスのコンストラクターを呼び出すために適切に使用しています。コンストラクターをどのように定義するかについてはConstructor()、異なるコンストラクターの本体ではなく、別のメソッドを使用するのはなぜですか? クラスの 1 つの新しいインスタンスを作成するときにのみ呼び出すことを計画している場合は、次のように実際のコンストラクターに戻ることをConstructor()お勧めします。Constructor()

namespace Test
{
    public class ClxBasic
    {
        public ClxBasic()
        {
            // Do Something
        }
    }

    public class ClxObject : ClxBasic
    {
        public ClxObject() : base()
        {
            // Do Something
        }
    }

    public class ClxSprite : ClxObject
    {
        public ClxSprite() : base()
        {
            // Do Something
        }
    }
}

Update()オブジェクトの実際のクラスに応じて、適切な関数を呼び出せるようにするためには、 virtualキーワードとoverrideキーワードを使用してこれを実現します。次のように使用します。

namespace Test
{
    public class ClxBasic
    {
        // Define the base function that can be overridden
        // in subclasses.
        public virtual void Update()
        {
            // Do Some Updates
        }
    }

    public class ClxObject : ClxBasic
    {
        // We're overridiung the base function, so we
        // must mark this function as an override.
        public override void Update()
        {
            // Do Some Updates
        }
    }

    public class ClxSprite : ClxObject
    {
        // We're overridiung the base function, so we
        // must mark this function as an override.
        public override void Update()
        {
            // Do Some Updates
        }
    }
}

Update()から派生したクラスのインスタンスであるオブジェクトを呼び出すと、そのオブジェクトの継承チェーンClxBasicの最上位Update()関数が呼び出されます。例えば:

ClxBasic clxBasic = new ClxBasic();   // Calls ClxBasic.Update()
ClxBasic clxObject = new ClxObject(); // Calls ClxObject.Update()
ClxBasic clxSprite = new ClxSprite(); // Calls ClxSprite.Update()

さらに、関数で親Update()の関数を呼び出す場合は、 base キーワードを使用できます。例えば:Update()

public class ClxSprite : ClxObject
{
    // We're overridiung the base function, so we
    // must mark this function as an override.
    public override void Update()
    {
        base.Update(); // Will call ClxObject's Update() function
        // Do Some Updates
    }
}
于 2012-06-23T13:37:03.280 に答える
0

あなたの説明に基づいて、あなたの目標は、異なるゲーム クラス間でポリモーフィックな動作を実現することのようです。より良い解決策は、異なるゲーム クラスが実装する必要があるインターフェイスを定義することです。次に、すべてのゲーム オブジェクトを配列リストなどの 1 つの汎用コンテナーに配置し、マスター ゲーム ループでオブジェクト リストを反復処理して、全体的な更新ごとに各オブジェクトの update メソッドを呼び出すことができます。私は次のようにクラスを設計します:

interface IUpdatable {
   void doUpdate();
}

class GameClassA : IUpdatable {
   void doUpdate() { // }
}

class GameClassB : IUpdatable {
   void doUpdate() { // }
}

目標は、異なるクラスのオブジェクト間でポリモーフィックな動作を実現することですが、必ずしもデータと共通の機能を共有する必要はありません。継承によってポリモーフィズムを実現することもできますが、この場合は、単純なインターフェイスと構成によって実現する方が適切です。

于 2012-06-23T13:11:34.410 に答える