c# - 对虚拟/新/覆盖的困惑

标签 c# virtual overriding new-operator keyword

我对 virtual/new/override 这件事有点困惑。这是一个例子:

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

class B : A
{
    public virtual void mVVirtual() { Console.WriteLine("B::mVVirtual"); }
}

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


class Test
{
    static void Main()
    {
        B b1 = new C();
        b1.mVVirtual();    //C::mVVirtual ... I understand this

        A a2 = new C();
        a2.mVVirtual();    //A::mVVirtual ... ???
    }
}

我不明白为什么在第二次调用中我们得到 A::mVVirtual。我通常用这个“算法”来处理这些问题:

  1. 检查保存对象引用的变量类型,以获取名为 mVVirtual 的实例方法?没有...但是有一个具有该签名和名称的虚拟方法!
  2. 虚方法?然后让我们检查 a2 (C) 所持有的对象的类型,以了解该方法的重写。它有一个 -> 执行 C::mVVirtual!

我的“算法”哪里错了?我真的对此感到困惑,非常感谢您的帮助。

最佳答案

以下是您对虚拟方法的看法。类的每个实例都有“框”来保存方法。当您将方法标记为 virtual 时它说制作一个新的“盒子”并在其中放入一个方法。当您将方法标记为 override 时在派生类中,它保留了基类中的“框”,但在其中放置了一个新方法。

所以这里有一个类 A和一个名为 mVVirtual 的方法标记为 virtual .这表示创建一个名为 mVVirtual 的新“框”并在其中放入一个带有定义的方法

Console.WriteLine("A::mVVirtual"); 

然后你有一个派生类B和一个名为 mVVirtual 的方法标记为 virtual .这表示创建一个名为 mVVirtual 的新“框”并在其中定义一个方法

Console.WriteLine("B::mVVirtual"); 

特别是从 A 继承的“盒子”是隐藏的!类型为 B 的对象无法看到它派生自 B 的类或类.

然后你有一个派生类C和一个名为 mVVirtual 的方法标记为 override .这表示取名为 mVVirtual 的“盒子”继承自 B并在其中定义不同的方法

Console.WriteLine("C::mVVirtual"); 

现在,当你有

B b1 = new C(); 
b1.mVVirtual();

你告诉编译器 b1B这样b1.mVVirtual()查看“盒子”mVVirtual并找到有定义的方法

Console.WriteLine("C::mVVirtual"); 

因为b1真的是C这就是“盒子”里的东西mVVirtual对于 C 的实例.

但是当你有

A a2 = new C(); 
a2.mVVirtual();

你告诉编译器 a2是一个 A所以它在“盒子”中查找并找到

Console.WriteLine("A::mVVirtual");

编译器无法知道a2真的是C (您将其键入为 A )所以它不知道 a2实际上是从隐藏“盒子”的类派生的类的实例mVVirtualA 定义.它知道的是 A有一个名为 mVVirtual 的“盒子”因此它会发出代码来调用该“盒子”中的方法。

所以,试着简明扼要地说:

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

定义了一个类,它有一个全名为 A::mVVirtual 的“盒子”但你可以用名字来指代 mVVirtual .

class B : A 
{
    // "new" method; compiler will tell you that this should be marked "new" for clarity.
    public virtual void mVVirtual() { Console.WriteLine("B::mVVirtual"); }
}  

定义了一个类,它有一个全名为 B::mVVirtual 的“盒子”但你可以用名字来指代 mVVirtual .引用B.mVVirtual不会引用全名的“盒子”A::mVVirtual ;类型为 B 的对象无法看到该“框” s(或派生自 B 的类)。

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

定义了一个类,它接受全名 B::mVVirtual 的“盒子”并在其中放入不同的方法。

然后

A a2 = new C(); 
a2.mVVirtual();

a2是一个 A这样a2.mVVirtual在“盒子”中查找全名 A::mVVirtual并调用该“框”中的方法。这就是为什么你看到

A::mVVirtual

在控制台上。

还有另外两个方法注释器。 abstract制作一个新的“盒子”并没有将方法定义放入“盒子”中。 new创建一个新的“盒子”并将方法定义放在“盒子”中,但不允许派生类将它们自己的方法定义放在“盒子”中(如果你想这样做,请使用 virtual)。

抱歉啰嗦,但希望对您有所帮助。

关于c# - 对虚拟/新/覆盖的困惑,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2065780/

相关文章:

ios - 如何使用 Xcode 6.3 Beta2 在 Swift 中覆盖 SuperClass 的 setter?

c# - 从文本文件中删除 <div>?

delegates - 通过委托(delegate)执行可重写方法时,Invoke() 和 BeginInvoke() 的行为不同

Java虚拟文件系统应用

c++ - 虚拟类有什么好处?

joomla - 更改 Joomla 3.2 标签的位置

c# - 使用 C# 为字典中的一个键添加多个位图值

c# - 在运行时确定我自己的应用程序的哈希值?

c# - 如何使用 C# 在字节数组中的 Web 表单中显示图像

class - 在子类中覆盖返回协变类型的下标