C# New关键字:为什么不调用派生方法?
我有三个简单的课程:C# New关键字:为什么不调用派生方法?,c#,inheritance,C#,Inheritance,我有三个简单的课程: 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.Wr
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
我理解ab=newc()
创建了C的新对象类型。所以输出应该是C。或者,当我们使用重写方法而不强制转换时,调用重写方法是一种特殊行为
为什么会这样?因为我们没有使用任何对
B
类的引用。如果您使用((C)B)。Write()代码>
使用new
关键字并不是覆盖C的Write
方法,而是创建一个只为C定义的新方法。因此,对于C,实际上有两个方法名为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
的实际派生类型,否则将调用基类的方法。我现在已经很晚了,没有回答这个问题,但我需要这种行为,以防万一其他人需要,我会分享它。
例如,要获得beheavior,您需要使用接口
interface Writer{
void write;
}
class A : Writer
{
void Writer.Write()
{
Console.Write("A");
}
}
其他的也一样。正如您所看到的,您必须实现它的显式性,并将其称为显式
A c = new C();
((Writer) c).write()
) 因为这就是新关键字的工作原理。通常被称为“成员隐藏”或“隐藏”,谨慎使用它-当您期望代码执行其他操作时,它可能会非常刺耳。我很抱歉我的愚蠢问题,但是为什么这些代码ab=new C();b、 Write()代码>调用重写的方法?我的意思是ab=newc()
创建C
的新对象类型。所以输出应该是C
。或者,当我们在不强制转换的情况下使用重写方法时,调用重写方法是一种特殊行为?要访问隐藏另一个方法的方法,需要对定义隐藏的类型的强类型引用,而不是基引用。同样的规则也适用于显式实现的接口。它基本上不是“正确的”继承,因此继承层次结构的实施方式与标准重写方法调用的方式不同。很难解释,但你说你的变量c
是a
类型,所以你的编译器知道“c是a的一个实例”,不知道它实际上是更派生的类型。当您在其上调用方法Write
时,它将调用在A上定义的方法,该方法实际上被B覆盖。您的基类A
不知道在C上定义的新方法(与WriteLine
方法完全相同,new
就是这样做的,创建一个新方法),因此,除非您将其强制转换为C
,否则将调用基类的方法。@Steppup在中编辑了它:)