【问题标题】:Need to understand the below code for C# virtual methods需要了解以下 C# 虚方法的代码
【发布时间】:2012-07-06 13:31:12
【问题描述】:

这是一个显示虚方法的小代码。

class A
{
  public virtual void F() { Console.WriteLine("A.F"); }
}
class B: A
{
  public override void F() { Console.WriteLine("B.F"); }
}
class C: B
{
  new public virtual void F() { Console.WriteLine("C.F"); }
}
class D: C
{
  public override void F() { Console.WriteLine("D.F"); }
}

class Test
{
  static void Main() 
  {
    D d = new D();
    A a = d;
    B b = d;        

    a.F();
    b.F();        
 }
}

此代码正在打印以下输出:

B.F
B.F

我不明白为什么 a.F() 会打印 B.F ?

我认为它会打印 DF,因为 B 类覆盖了 A 类的 F(),然后使用“new”关键字将该方法隐藏在 C 类中,然后在 D 类中再次被覆盖。所以最后 DF 保留.

但它没有这样做。你能解释一下为什么要打印 B.F 吗?

【问题讨论】:

    标签: c# .net inheritance virtual-functions


    【解决方案1】:

    正如其他人已经指出的那样,C 中的 new 关键字隐藏了 F 的重载,因此在 C 或 D 中找不到合适的 F 重载。

    如果您需要有关 C# 找到正确重载的更多详细信息,请阅读 那两个:

    Jon Skeet: C# in Depth, chapter Overloading

    Visual Studio 2010: Breaking changes, here: overload resolution

    【讨论】:

      【解决方案2】:

      与允许多态性的方法覆盖不同,使用 new 关键字隐藏方法只是命名问题(请注意,使用 new 只会删除您正在隐藏某些内容的警告)。

      C类中,当你声明时:

      new public virtual void F() { ... }
      

      您在这里定义了一个与超类的F() 无关的全新方法,它恰好具有相同的名称。

      F 的实例分配给AB 类型的变量时,使用这些变量调用F() 将指向超类定义的方法。

      想象一下,如果您没有调用C 的方法F(),而是调用了一些不同的方法,例如G()。以下代码无法编译:

      a.G();
      b.G();
      

      由于变量静态类型为AB,编译器看不到新声明的方法。在您的示例中情况相同,只是超类恰好有名为 F() 的原始方法来调用。

      【讨论】:

        【解决方案3】:
        A a = d;
        a.F();
        

        它会找到F(),如下所示。

        1. 先入class A
        2. 然后在class B
        3. 然后在class C
        4. 然后在class D

        现在F() 将在AB 中找到。因此B.F() 将被调用。在class C F() 中是不同的(因为它是新实现并且不会从 A/B 覆盖)。所以在第 3 步中,将找不到 c.F()。在D类中,它覆盖了C创建的新函数,因此也找不到。

        由于 new 关键字,结果代码如下(关于虚拟覆盖)

            class A
            {
                public virtual void F() { Console.WriteLine("A.F"); }
            }
            class B: A
            {
                public override void F() { Console.WriteLine("B.F"); }
            }
            class C: B
            {
                public virtual void F1() { Console.WriteLine("C.F"); }
            }
            class D: C
            {
                public override void F1() { Console.WriteLine("D.F"); }
            }
        

        【讨论】:

        • 谢谢 Tilak 和大家,我现在明白了 :-)
        【解决方案4】:

        A.F 被 B.F 覆盖。因此,当 A.F 被调用时,它会执行 B.F。B.F 被“连接”到 'A.F'。

        现在 C.F 用 new 关键字隐藏 B.F。 C.F 未连接到 B.F/A.F。当您创建 C 并调用 F() 时,它将执行 C.F.如果将 C 转换为类型 A 或 B,并调用 F,它将执行 B.F,因为 B.F 和 A.F 是连接的。

        C.F 被 D.F 覆盖。它们是相连的。当调用 C.F 或 D.F 时,它将执行 D.F。现在,当您将对象 D 转换为 A 或 B 并调用 F() 时,它将调用 B.F.

        希望这有助于使其更清晰。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-11-10
          • 2021-02-06
          • 2016-06-19
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多