【问题标题】:Base Class = New Derived Class. How does this work?基类 = 新派生类。这是如何运作的?
【发布时间】:2015-10-14 17:12:14
【问题描述】:

假设我有一个名为 Enemy 的基类和一个名为 Ogre 的派生类。

这两种方式创建实例有什么区别:

Enemy newOgre = new Ogre();

Ogre newOgre = new Ogre();

【问题讨论】:

  • 最好使用IEnemy 接口而不是Enemy 基类。如果你不会创建新的 Enemies 作为基类,接口会更合适
  • 这个创建没有太大的区别,除了引用Enemy类型的新对象将只提供基类接口。
  • 没有以不同的方式创建它们。您正在对相同创建的对象执行不同的操作(即以不同的方式存储它们)。
  • 你想知道什么?它是如何工作的(例如,如何找到虚拟方法——搜索 v-table 查找)?或者如何使用(搜索继承)?

标签: c# class


【解决方案1】:

实际上,创建实例的那段代码只有new Ogre()。等号左边的内容与创建实例无关。

第一条语句只是将创建的实例分配给Enemy 类型的变量。第二个是将其分配给Ogre 类型的变量。

所以你有两个不同类型的变量指向相同类型的对象,即Ogre

变量(等号的左侧)仅决定您可以从对象访问的内容。例如,如果Ogre 类有一个不是从Enemy 继承的方法,那么使用Enemy 变量,您将无法访问它。

请注意,变量不会影响对象的行为方式。例如,如果Ogre 覆盖了在Enemy 中定义的方法,它会做一些不同的事情。使用Enemy 类型的变量在Ogre 的实例上调用此方法将导致调用Ogre 中的重写方法,而不是Enemy 中的方法,

例如,考虑这些类:

public class Enemy
{
    public virtual void Test()
    {
        Console.WriteLine("enemy");
    }
}

public class Ogre: Enemy
{
    public override void Test()
    {
        Console.WriteLine("ogre");
    }
}

现在如果你这样做:

Orge enemy = new Orge();
enemy.Test();

控制台会打印“ogre”。

如果你这样做:

Enemy enemy = new Ogre();
enemy.Test();

控制台仍会打印“orge”。

【讨论】:

  • 我觉得你还应该提到,如果你在 Ogre 中隐藏了一个方法并将一个 Ogre 分配给一个 Enemy 变量,使用 Enemy 变量调用该方法将调用基本方法,而不是隐藏方法。
【解决方案2】:

除了 Yacoub 的回答之外,在这种情况下,Enemy 不会包含 Ogre 拥有的属性和方法。

public class Enemy
{
    public int Property1 { get; set; }
    public int Property2 { get; set; }
}

public class Ogre : Enemy
{
    public int Property3 { get; set; }
}

假设你继承了 Ogre 类中的 Enemy。这意味着您的 Ogre 将有效地包含 3 个属性:1,2 和 3。

在您的示例中,您将 Ogre 分配给 Enemy 类型。 Enemy 类型不包含“Property3”,因此您将无法在 Enemy 转换对象中使用扩展类“Ogre”。

//This will work
Ogre newOgre = new Ogre();
int newInt = newOgre.Property3;

//This wont.
Enemy newOgre = new Ogre();
int newInt = newOgre.Property3;

【讨论】:

    【解决方案3】:

    声明一个Enemy 类型的变量 并引用一个新的Ogre 对象。另一个声明了一个Ogre 类型的变量并引用了一个新的Ogre 对象。

    一些差异(并非详尽的列表):

    • 您不能在Enemy 类型的变量上调用Ogre 的非继承方法。
    • Ogre 中被覆盖的Enemy 的任何虚拟方法在任一变量上调用时都将使用Ogre's 实现。

    【讨论】:

      【解决方案4】:

      假设你的 Enemy 类如下所示:

      public class Enemy
      {
          public void Attack() { }
          public void Move() { }
      }
      

      你的食人魔类是这样的:

      public class Ogre : Enemy
      {
          public void OgreSmash() { }
      }
      

      使用 Enemy 变量,您只能访问 Attack()Move(),但不能访问带有 Ogre 变量的 OgreSmash(),您将可以访问基类和派生类的方法。

      【讨论】:

        【解决方案5】:

        这里

        Enemy newOgre = new Ogre();
        

        您不能使用后来添加到类 Ogre 并且不在基类中的 newOgre 调用方法,而使用其他变量可以调用这些方法。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2023-03-15
          • 2019-04-05
          • 1970-01-01
          • 2022-01-23
          • 2023-03-19
          • 1970-01-01
          • 2017-06-21
          • 2016-02-23
          相关资源
          最近更新 更多