C#继承和成员隐藏

C#继承和成员隐藏,c#,inheritance,C#,Inheritance,我正在Unity游戏引擎中开发一个2D太空射击游戏 我有一个基类,包含所有敌方太空船共享的变量,该基类包含的函数将由派生类的每个实例调用。以这个void Start()函数为例: 基类 public class EnemyBaseScript : MonoBehaviour { // some public/protected variables here protected void Start () { // some initializati

我正在Unity游戏引擎中开发一个2D太空射击游戏

我有一个基类,包含所有敌方太空船共享的变量,该基类包含的函数将由派生类的每个实例调用。以这个
void Start()
函数为例:

基类

public class EnemyBaseScript : MonoBehaviour 
{
    // some public/protected variables here

    protected void Start () 
    {
         // some initializations shared among all derived classes
    }
.
.
.
}
public class L1EnemyScript : EnemyBaseScript 
{       
    // Use this for initialization
    void Start () 
    {
        base.Start ();  // common member initializations
        hp = 8;         // hp initialized only for this type of enemy
        speed = -0.02f; // so does speed variable
    }
}

派生类

public class EnemyBaseScript : MonoBehaviour 
{
    // some public/protected variables here

    protected void Start () 
    {
         // some initializations shared among all derived classes
    }
.
.
.
}
public class L1EnemyScript : EnemyBaseScript 
{       
    // Use this for initialization
    void Start () 
    {
        base.Start ();  // common member initializations
        hp = 8;         // hp initialized only for this type of enemy
        speed = -0.02f; // so does speed variable
    }
}
我想你明白了。我希望在
base.Start()
函数中完成公共初始化,并在此
Start()
函数中完成特定于类的初始化。然而,我得到了警告:

Assets/Scripts/L1EnemyScript.cs(7,14):警告CS0108:
L1EnemyScript.Start()
隐藏继承的成员
EnemyBaseScript.Start()
。如果要隐藏,请使用新关键字


我缺乏OOP和C#方面的经验,那么我认为正确的方法是什么呢?此警告是什么意思?如何正确执行此警告?

您需要告诉编译器应该覆盖
Start

protected virtual void Start () { ... }
事实上,您在派生类中有意重写它:

protected override void Start ()  { ... }
参见文件以获取参考;还有更多的信息

当前代码定义了两个独立的
Start
方法,它们恰好共享相同的名称,但在其他方面没有关联。

在C#中,继承具有相同函数签名的函数将隐藏上一个函数

:

但是,隐藏函数可能不是您想要的:

class Base
{
   public static void F() {}
}
class Derived: Base
{
   new private static void F() {}   // Hides Base.F in Derived only
}
class MoreDerived: Derived
{
   static void G() { F(); }         // Invokes Base.F
}
相反,您可以做的是使基本函数“虚拟”:

然后我们可以覆盖它:

public class L1EnemyScript : EnemyBaseScript 
{       
    // Use this for initialization
    public override void Start () 
    {
        base.Start ();  // common member initializations
        hp = 8;         // hp initialized only for this type of enemy
        speed = -0.02f; // so does speed variable
    }
}
在C#中,默认情况下方法/属性是非虚拟的。如果希望在子类中重写方法/属性,则必须声明该方法/属性
virtual
。如果没有,则:

EnemyBaseScript s = new LIEnemyScript();
s.Start(); // calls EnemyBaseScript.Start()

您想要的是使方法在基类中成为虚拟的,并在子类中重写它

class EnemyBaseScript
{
    protected virtual void Start()
    {
        //...
    }
}

class L1EnemyBaseScript : EnemyBaseScript
{
    protected override void Start()
    {
        base.Start();
        //...
    }
}

嗯。我一直认为,
虚拟
函数是空的,以后可以通过
重写
来填充,我认为,这会完全重写虚拟函数(忽略其中的内容),并使以前在虚拟函数中编写的代码变得无关。现在我了解到它是对基本
Start()
的一种扩展,这非常好,正是我所需要的。如果我弄错了,请纠正我,谢谢你的回答。@Varaquilex:重写一个方法会使被重写的代码变得不相关(除非你在重写中调用
base.Start
)。为什么您认为它在扩展?噢,即使我们重写它,我调用函数(
base.start()
)的方式也会触发以前编写的代码。我认为这是不可能的后,压倒它。现在一切都清楚了:)不,瓦拉奎莱克斯。这些都是
抽象的
成员。我浏览了互联网,你简洁的例子是唯一能让我“点击”的东西。非常感谢。
class EnemyBaseScript
{
    protected virtual void Start()
    {
        //...
    }
}

class L1EnemyBaseScript : EnemyBaseScript
{
    protected override void Start()
    {
        base.Start();
        //...
    }
}