我希望我能正确解释这个问题,这对我来说有点混乱。
我一直在研究类似于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()时,它会转到底部的Update,即位于ClxBasic中的Update,尽管该对象是ClxObject或ClxSprite或其他派生类。
我也有一个有限的修复,通过在foreach循环中将ClxBasic更改为ClxSprite,您可以正确调用该类构造函数方法。但是,在基于覆盖方法的库创建自定义类时,将调用较低的Update。
但是,限制是你不能添加我没有专门计划的类。例如,如果我要从ClxSprite派生类Player并覆盖Update()方法,它将被添加到GlobalObjects列表中,但是,永远不会调用它的更新,它将最高的是ClxSprite。
我想要它的工作方式是,在Game1.cs中我想能够将FlxG.Update()置于Game.Update()循环中,并且能够创建对象并让我的框架处理其余部分。
我希望我有点意义,整个事情感觉就像某种继承开始,有点让我的大脑受伤。
答案 0 :(得分: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。基本上,您的基类有一个非虚方法,可以驱动一个调用虚拟(或抽象)方法的算法;子类可以覆盖以创建自己的版本。
答案 1 :(得分:1)
您正在使用base()
来调用基类的构造函数。至于如何定义构造函数,为什么Constructor()
是一个单独的方法,而不是不同构造函数的主体?如果您只打算在为其中一个类创建新内容时调用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()
个函数调用其父级的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
}
}
答案 2 :(得分:0)
根据您的描述,您的目标似乎是在不同的游戏类之间实现多态行为。更好的解决方案是定义不同游戏类必须实现的接口。然后,您可以将所有游戏对象放在一个通用容器中,例如数组列表,然后让主游戏循环遍历对象列表,并在每次整体更新期间调用每个对象的更新方法。我会设计这样的类:
interface IUpdatable {
void doUpdate();
}
class GameClassA : IUpdatable {
void doUpdate() { // }
}
class GameClassB : IUpdatable {
void doUpdate() { // }
}
等
您的目标是在不同类的对象之间实现多态行为,但不一定要共享数据和常用功能。虽然你也可以通过继承来实现多态,但在这种情况下通过简单的接口和组合可以更好地实现。