2012-06-23 69 views
1

我希望我能解释这个问题,对我来说有点令人困惑。如何调用顶级构造函数?

我一直在研究类似于flixel的游戏库,但是使用C#的XNA框架而不是Flash。现在的课程布局就是这样的。

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()它进入底部更新,所述一个位于ClxBasic,尽管对象是一个或ClxObject或ClxSprite其他派生的类。

我有一个有限的修复,通过在foreach循环中将ClxBasic更改为ClxSprite,您可以正确调用该类的构造方法。但是,当根据重写方法的库创建自定义类时,将调用较低的更新。

但是,限制是你不能添加我没有明确规划的类。例如,如果我要从ClxSprite派生一个类Player并覆盖Update()方法,它将被添加到GlobalObjects列表中,但从来没有调用过它的更新,它将会是ClxSprite的最高版本。

它的工作方式是,在Game1.cs我想就能够把FlxG.Update()在Game.Update()循环,只是能够创建对象,并有我的框架处理其余的。

我希望我已经有了一些感觉,整个事情感觉像某种形式的遗传开始,有点让我的大脑受伤。

回答

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

但孩子的方法是不需要调用基之一。

另一方面,构造函数始终需要(最终)调用基础构造函数。

现在,如果你想要一个基类方法到总是被称为某些处理的一部分,你可以使用template method pattern。基本上你的基类有一个非虚方法来驱动一个调用虚拟(或抽象)方法的算法;子类可以重写以创建自己的版本。

+0

这是否也调用它下面的所有方法呢?你能告诉我如何用三个班而不是两个班来完成吗?所有类都应该调用它下面的构造函数,以使Update循环正常工作。 – redcodefinal

+0

@ user406470:我添加了第三类;它的工作原理与第二个一样... –

+0

这很完美。谢谢,一切都如此。我真的很感激这个帮助,这让我疯狂。 – redcodefinal

0

根据您的描述,您的目标似乎是实现不同游戏类别之间的多态行为。更好的解决方案是定义不同游戏类必须实现的接口。然后,您可以将所有游戏对象放在一个通用容器中,例如数组列表,然后让主游戏循环遍历对象列表,并在每次全面更新期间调用每个对象的update方法。我想设计的类是这样的:

interface IUpdatable { 
    void doUpdate(); 
} 

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

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

你的目标是实现不同类的对象之间的多态行为,但不一定共享数据和常用功能。虽然通过继承也可以实现多态,但在这种情况下,通过简单的接口和组合可以更好地实现。

1

您正在正确使用base()来调用基类的构造函数。至于你如何定义你的构造函数,为什么Constructor()是一个单独的方法,而不是不同构造函数的主体?如果你只在调用Constructor()当你创建一个类的新insance计划,我会建议移动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()功能,取决于您的对象的实际类别,您可以使用virtualoverride关键字完成此操作。你会使用它们像这样:

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 
     } 
    } 
} 

当你的对象是从ClxBasic派生的类的实例上调用Update(),在顶级Update()函数对象继承链将被调用。例如:

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

此外,如果你希望你的Update()函数调用他们的父母的Update()功能,您可以使用base keyword。 例如:

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 
    } 
} 
+0

感谢您的描述性答案!我有这样的构造函数的原因是因为我不能在下面调用一个构造函数,因为我不知道这个可爱的公共ClxObject():base()技巧。我只是在我发布这个问题之前就补充说,所以我不完全确定它的限制。我将其固定在我的库代码中。再次感谢! – redcodefinal