0

我当然可以自己写一个虚拟测试来回答这个问题,但我想知道人们对这个问题的看法。这里是:

当我们同时重载和覆盖时会调用哪个方法?我只考虑类型重载而不是重载,并且当类型重载相关时。

让我举个例子:

class AA {}
class BB : AA {}

class A {
    public virtual void methodA(AA anAA) { Console.Write("A:methodA(AA) called"); }
    public virtual void methodA(BB aBB) { Console.Write("A:methodA(BB) called"); }
}

class B : A {
    public override void methodA(AA anAA) { Console.Write("B:methodA(AA) called"); }
}

new B().methodA(new BB());     // Case 1
new B().methodA(new AA());     // Case 2
new B().methodA((AA)new BB()); // Case 3

你能说出情况 1、2 和 3 会发生什么吗?

我个人认为超载是邪恶的,并且没有一致的想法可以导致可预测的答案。这完全基于编译器+虚拟机中实现的约定。

编辑:如果您对为什么超载是邪恶的有疑问,您可以阅读Gilad Brach的博客文章

谢谢

4

3 回答 3

6

不,这是完全可以预测的。首先解析方法签名——即首先确定重载。然后,调用最被覆盖的方法。所以输出将是:

  • A:methodA(BB) 调用
  • B:methodA(AA) 调用
  • B:methodA(AA) 调用

在后两种情况下,将调用获取 AA 实例的方法,因为这是传入的引用类型,并且调用的是 B 的版本。请注意,即使这样也会产生相同的结果:

A instance = new B();
instance.methodA((AA)new BB()); // Case 3
于 2012-06-01T14:02:05.717 回答
4

当编译器确定要调用哪个方法时,从方法集中排除被覆盖的方法。请参阅成员查找算法。因此,当您调用methodAtype时,将构造B一组名称methodA来自 type及其基类型的成员:B

override B.methodA(AA)
virtual A.methodA(AA)
virtual A.methodA(BB)

然后ovveride从集合中删除修饰符的成员:

virtual A.methodA(AA)
virtual A.methodA(BB)

这组方法是查找的结果。之后,应用重载决议来定义要调用的成员。

  1. A.methodA(BB)被调用,因为它的参数匹配参数。
  2. A.methodA(AA)将被选中,但它是虚拟方法,所以实际上调用转到B.method(AA)
  3. 与选项 2 相同
于 2012-06-01T14:01:38.740 回答
0

我想结果会是这样

案例 1:Console.Write("A:methodA(BB) 调用");

案例 2:Console.Write("B:methodA(AA) 调用");

案例 3:Console.Write("B:methodA(AA) 调用");

在案例 3 中,它将看起来是它传递的类型,它是 B

于 2012-06-01T14:02:54.000 回答