c#中的虚方法和对象切片

The*_*ble 0 c# virtual-functions

我可以理解基本的对象切片,但有时当我们来到这样的例子时它会变得很混乱

using System;
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;
      C c = d;
      a.F();
      b.F();
      c.F();
      d.F();
   }
}
Run Code Online (Sandbox Code Playgroud)

输出:

B.F
B.F
D.F
D.F
Run Code Online (Sandbox Code Playgroud)

我想知道如何达到B类的"f()"函数

D d = new D();
A a = d;
a.F();
Run Code Online (Sandbox Code Playgroud)

如果它是:

A a = new A();
a.F()
//The result would be => A.F  
Run Code Online (Sandbox Code Playgroud)

但是在第一部分中,"a"的运行时间对象为"d",因此人们可能认为它是"DF"作为输出,所以它是如何出现在D和c以及B所以正确的输出是"BF"请帮我解决这个问题

Dan*_*zey 5

当您使用new定义与基类的方法同名的方法时,您隐藏了基类的实现。(这几乎总是一个坏主意,但偶尔有必要。)

当您使用这样的隐藏方法引用类时,它不是覆盖。因此,您用来引用对象的变量类型将决定您将获得哪个版本的方法。

当您new D()通过a或引用您的任何一个时b,您将其引用为一种不知道new该方法版本的类型。因此,这两个调用都使用他们知道的方法的最派生版本。不存在用于覆盖B.F()在任一C(因为它new)或D(因为它仅覆盖的方法C)。因此,B.F()在这两种情况下都被调用。

当您通过c或引用类时d,将使用覆盖的方法 in D,正如您所期望的。


Sae*_*ati 5

嗯,AMAIK,你的问题基本上不是关于对象切片.它更多的是区别使用之间new,virtualoverride关键字.

我将提出一个更容易理解的例子.考虑以下代码:

public class Animal
{
    public virtual void Sleep()
    {
        Console.WriteLine(@"I'm an animal, and I want to sleep.
        I just close my eyes");
    }
}

public class Mammal : Animal
{
    public override void Sleep()
    {
        Console.WriteLine(@"I'm a mammal, thus basically an animal.
        Therefore, I both close my eyes, and need a warm place to sleep");
    }

    public bool HasBreasts
    {
        get
        {
            return true;
        }
    }
}

public class Human : Mammal
{
    public new virtual void Sleep()
    {
        Console.WriteLine(@"I'm a human. 
        I'm so proud that I don't consider myself as an animal. 
        I sleep in a cozy place, 
        and I need a lot of money to sleep well");
    }

    public virtual void FallInLove();
}

public class Worker : Human
{
    public override void Sleep()
    {
        Console.WriteLine(@"I'm a worker, and I'm under poverty line. 
        I have to work hard, 
        and I really don't know what they mean by a good sleep");
    }

    public override void FallInLove()
    {
        Console.WriteLine(@"What is love? 
        I need bread to survive. 
        I'm in the bottom-most level of Mozlow's pyramid of needs.");
    }
}
Run Code Online (Sandbox Code Playgroud)

现在让我们分析每个关键字.由于a Worker基本上和基本上是人类,因此它HasBreasts也可以FallInLove().但是等一下.一个工人(没有冒犯,只是一个有趣的例子)没有钱坠入爱河.然后一个工人可能override会这样做,忘记爱情.

另一方面,所有动物都可以睡觉.他们只是闭上眼睛睡觉.然而,由于哺乳动物是热血动物,它们需要一个温暖的地方.所以他们延长了祖先的睡眠习惯.

但另一方面,人类定义了一个完全new水平的睡眠.他想要对他的祖先进行革命.他不想被称为Animal,所以他Sleep()从头开始重新定义.

现在根据@DanPuzey的解释,您可以阅读其余的故事.它在现实世界中是有意义的.