虚拟方法& c#中的对象切片

时间:2013-11-14 13:48:39

标签: 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();
   }
}

输出:

B.F
B.F
D.F
D.F

我想知道如何达到B类的“f()”功能

D d = new D();
A a = d;
a.F();

如果是:

A a = new A();
a.F()
//The result would be => A.F  

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

2 个答案:

答案 0 :(得分:5)

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

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

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.");
    }
}

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

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

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

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

答案 1 :(得分:4)

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

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

当您通过new D()a引用b时,您将其引用为不了解该方法的new版本的类型。因此,这两个调用都使用他们 知道的方法的派生版本。 B.F()中的C没有覆盖(因为它是new)或D(因为它只会覆盖C中的方法)。因此,在这两种情况下都会调用B.F()

当您通过cd引用该课程时,会使用D中的重写方法,如您所料。