新关键字:为什么不调用派生方法

本文关键字:派生 方法 调用 为什么不 关键字 | 更新日期: 2023-09-27 18:36:20

我有简单的三个类:

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

我正在创建对象并调用它们的方法:

A a = new A();
a.Write();
A b = new C();
b.Write();
C c = new C();
c.Write();

输出将是:ABC

我不明白的是为什么这些代码会产生B

A b = new C();
b.Write();

我认为它应该是C.但是,我测试了很多次,它总是B.

我知道A b = new C()会创建新的 C 对象类型。所以输出应该是 C。还是当我们使用重写方法而不进行强制转换时调用重写方法是一种特殊行为?

为什么会这样?因为我们没有使用任何对B类的引用。

新关键字:为什么不调用派生方法

如果你使用((C)b).Write();它会起作用

使用 new 关键字,您不会覆盖 C 的Write方法,而是创建一个仅为 C 定义的新方法。因此,对于您的 C,您实际上有 2 个方法,方法名称为 Write

A c = new C();
c.Write();          //Output "B", you're calling the overridden method    
((C)c).Write();     //Output "C", you're calling the method defined on C
//or
(c as C).Write();

当您将 c 定义为 C 时也会发生同样的情况:

C c = new C();
c.Write();          //Output "C"    
((A)c).Write();     //Output "B"

在第一个示例中,您将调用在 C 上定义的新方法。在第二行中,您将从 A 调用 Write 方法,该方法被 B 覆盖,因此输出"B"

编辑:(更多解释)

变量 c 是 A 类型,所以这就是编译器所知道的"c 是 A 的实例",不知道它实际上是一个更派生的类型。当您调用方法Write时,它将调用在 A 上定义的方法(该方法被 B 覆盖)。基类 A 不知道在 C 上定义的新方法(这就是new所做的,创建一个新方法),所以除非你把它强制转换为 C 让编译器知道实际的派生类型的c,否则将调用基类的方法。

我现在真的很晚了,没有回答这个问题,但我需要这种行为,以防万一其他人需要它,我会分享它。为了获得这种行为,您需要使用接口,例如

interface Writer{
 void write;
}
class A : Writer
{
    void Writer.Write()
    {
        Console.Write("A");
    }
}

其他人也是如此。如您所见,您必须实现它的显式性以及将其称为显式性。

A c = new C();
((Writer) c).write()

;