【问题标题】:Play with inheritance [duplicate]玩继承[重复]
【发布时间】:2018-04-08 12:43:34
【问题描述】:

当我写 a=c; 时,我只是想了解正在发生的事情;当我检查“a”的类型时,它显示为“C”类。现在我的问题是,如果“a”指向“c”,那么为什么它的行为不像指针“c”。 p>

 class Program
    {
        static void Main(string[] args)
        {
            C c = new C();
            A a = new A();
            Console.WriteLine(a.GetType());
            a = c;
            Console.WriteLine(a.GetType());
            a.Show();
            c.Show();
            Console.ReadLine();
        }
    }
class A
{
    public virtual void Show()
    {
        Console.WriteLine("A.Show()");
    }
}

class B : A
{
    public override void Show()
    {
        Console.WriteLine("B.Show()");
    }
}

class C : B
{
    public new void Show()
    {
        Console.WriteLine("C.Show()");
    }
}

输出:

【问题讨论】:

  • "为什么它的行为不像指针 "c"。"这是什么意思?
  • 我的意思是,为什么它调用B类的“Show()”。
  • 您使用了new 关键字来禁止编译器警告。粗略地说“您确定要这样做,这可能是错误的”。原来你不确定。将 C.Show 的名称更改为 ShowAlso(),您不再需要 new 关键字。当你完全运行程序时会发生什么。

标签: c# oop inheritance


【解决方案1】:

这是因为您使用了new 关键字。

new 关键字只是隐藏底层方法并将其替换为新方法。当您将对象转换为A(甚至B)时,您使用的是B 中的隐藏方法,而不是C 中的新方法。

您可以在文档herehere 中了解更多信息。

【讨论】:

  • 我知道 new 关键字隐藏了底层方法但是我更感兴趣的是当我将“c”类指针分配给“a”然后使用 a.GetType() 检查 a 的类型,它引用类 C。这意味着现在 a 指向 C 的内存地址。那么为什么它不像指针 c 那样表现得像现在 "a" 和 "c" 都是一样的。
  • @SaurabhSaxena 因为 C 没有实现对 Show 方法的覆盖。该方法的最后一个覆盖是B。通过将 C 的实例强制转换为 A 变量,您将指示 C# 使用来自 A 的方法的最高级别 (B) 覆盖。
【解决方案2】:

其实就是'一个指针“c”'。但正如@John 所说,new 关键字是这里的问题。

如果您没有将类型设置为a 变量,结果将是您所期望的。

例如:

public static void Main()
{
    C c = new C();
    object a = c;
    Console.WriteLine(a.GetType()); // It still is of `C` type instead of object as you've set
    ((A)a).Show(); // Prints out "C.Show" 
    c.Show(); // Prints out "C.Show"
    Console.ReadLine();
}

一旦您期望Show 方法具有“A”类行为,它就充当A 已知方法。由于C 具有NEW 行为,因此A(或B)不知道,甚至有一个旧的Show(这是从B 继承的)以实现优势兼容性。

简历中:C 类的Show 方法是一个“巧合”同名的新方法。但它只有 C 类(并且是子类)知道。

【讨论】:

  • var a = c 基本上是C a = c,所以很明显它会打印C.Showa 的类型为 C。如果你写A a = c,它将打印B.Show
  • @w.b 我们这里有个坏蛋!对于询问的用户来说,这似乎不太明显。他的示例基于在他不太了解的继承上下文中对“相同内存指针”的多次引用,我试图让他足够清楚。如果您不喜欢我的回答,请给我投反对票,不要难过=)
  • 好吧,我没问题,只是想说你写了两次同样的东西,ca 都是 C 类型。
  • @w.b 我只是在评论这篇文章,你说得对。我是多余的,重复自己。我没有选择一个好的代码来举例说明我想要什么。我现在正在尝试保存它。感谢您的通知和建议 =)
  • 希望现在更好
【解决方案3】:

因为 C 中的 Show() 方法没有被覆盖。所以当你给 c 赋值 a 时,它没有 c 的行为,而是有 B 的行为.如果您希望 a 具有 c 类似的显示行为,则必须重写 Show() 方法。

using System;

public class Program
{
    public static void Main()
    {
        C c = new C();
        A a = new A();
        Console.WriteLine(a.GetType());
        a = c;
        Console.WriteLine(a.GetType());
        a.Show();
        c.Show();
        Console.ReadLine();
    }
}

class A
{
    public virtual void Show()
    {
        Console.WriteLine("A.Show()");
    }
}

class B : A
{
    public override void Show()
    {
        Console.WriteLine("B.Show()");
    }
}

class C : B
{
    public override void Show()
    {
        Console.WriteLine("C.Show()");
    }
}

【讨论】:

    【解决方案4】:

    为什么会调用B类的“Show()”

    因为a.Show() 是虚拟的,所以编译器会在层次结构中寻找被覆盖最多的版本,除非被覆盖的版本具有new 关键字,在这种情况下,方法实现隐藏在类层次结构的较高位置。在您的情况下,变量a 指向C 类型的对象,但C 类隐藏Show,因此编译器可见的最衍生版本是B.Show()

    【讨论】:

      【解决方案5】:

      如果您希望在第三行看到C.Show(),您需要将C类中的函数签名更改为

      public override void Show()
      

      “new”关键字用于将基类的方法、属性或事件隐藏到派生类中。

      当您编写 a=c; 时,您将 a 向下转换为 c,因此在运行时,层次结构中最接近 c 的函数将运行。

      【讨论】:

        猜你喜欢
        • 2015-04-28
        • 1970-01-01
        • 1970-01-01
        • 2012-06-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多