我可以自己回答这个问题,但是我想知道人们对这个问题的看法。这是:
当我们同时重载和覆盖时,将调用哪个方法?我只考虑类型重载而不是arity重载和类型重载是相关的。
让我举个例子:
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会发生什么吗?
我个人认为过载是邪恶的,并且没有一致的想法可以导致可预测的答案。这完全基于编译器+ vm中实现的约定。
编辑:如果您对过载是邪恶的原因有疑问,可以阅读Gilad Brach
中的博客文章由于
答案 0 :(得分:6)
不,这完全可以预测。首先解析方法签名 - 即首先确定重载。然后,调用最多重写方法。所以输出将是:
在后两种情况下将调用采用AA实例的方法,因为这是传入的引用的类型,并且它是被调用的B的版本。请注意,即使这样也会产生相同的结果:
A instance = new B();
instance.methodA((AA)new BB()); // Case 3
答案 1 :(得分:3)
当编译器确定调用哪个方法时,重写方法将从方法集中排除。请参阅member lookup算法。因此,当您在methodA
类型上致电B
时,会在methodA
类型中设置名为B
的成员,并构建其基本类型:
override B.methodA(AA)
virtual A.methodA(AA)
virtual A.methodA(BB)
然后将具有ovveride
修饰符的成员从set中删除:
virtual A.methodA(AA)
virtual A.methodA(BB)
这组方法是查找的结果。之后应用overload resolution来定义要调用的成员。
A.methodA(BB)
,因为它的参数与参数匹配。A.methodA(AA)
将被选中,但它是虚方法,所以实际调用转到B.method(AA)
答案 2 :(得分:0)
我认为结果将是这个
案例1:Console.Write(“A:方法A(BB)调用”);
案例2:Console.Write(“B:方法A(AA)调用”);
案例3:Console.Write(“B:方法A(AA)调用”);
在案例3中,它将看起来是它传递的类型,它是B