我对 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
。我通常用这个“算法”来处理这些问题:
- 检查保存对象引用的变量类型,以获取名为
mVVirtual
的实例方法?没有...但是有一个具有该签名和名称的虚拟方法! - 虚方法?然后让我们检查
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();
你告诉编译器 b1
是 B
这样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
实际上是从隐藏“盒子”的类派生的类的实例mVVirtual
由 A
定义.它知道的是 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/