Dav*_*vid 19 c# methods virtual inheritance overriding
给出以下C#类定义和代码:
public class BaseClass
{
public virtual void MyMethod()
{
...do something...
}
}
public class A : BaseClass
{
public override void MyMethod()
{
...do something different...
}
}
public class B : BaseClass
{
public override void MyMethod()
{
...do something different...
}
}
public class AnotherObject
{
public AnotherObject(BaseClass someObject)
{
someObject.MyMethod(); //This calls the BaseClass method, unfortunately.
}
}
Run Code Online (Sandbox Code Playgroud)
我想调用实际在A或B中找到的MyMethod(),假设传入的对象实际上是A或B的实例,而不是在BaseClass中找到的实例.做这样的事情:
public class AnotherObject
{
public AnotherObject(BaseClass someObject)
{
A temp1 = someObject as A;
if (A != null)
{
A.MyMethod();
}
B temp2 = someObject as B;
if (B != null)
{
B.MyMethod();
}
}
}
Run Code Online (Sandbox Code Playgroud)
我该怎么做?
Jon*_*anK 14
调用哪个方法是通过传递给AnotherObject构造函数的类型的多态来确定的:
AnotherObject a = new AnotherObject(new A()); // invokes A.MyMethod()
AnotherObject b = new AnotherObject(new B()); // invokes B.MyMethod()
AnotherObject c = new AnotherObject(new BaseClass()); //invokes BaseClass.MyMethod()
Run Code Online (Sandbox Code Playgroud)
对不起,但你完全错了; 这将违背虚拟方法的全部要点.如果someObject是,A那么A.MyMethod将被调用.如果someObject是,B那么B.MyMethod将被调用.如果someObject是a BaseClass而不是BaseClass从那时派生的类型的实例BaseClass.MyMethod将被调用.
让我们使用每个人最喜欢的例子:
class Animal {
public virtual void Speak() {
Console.WriteLine("i can haz cheezburger?");
}
}
class Feeder {
public void Feed(Animal animal) { animal.Speak(); }
}
class Cat : Animal {
public override void Speak() { Console.WriteLine("Meow!"); }
}
class Dog : Animal {
public override void Speak() { Console.WriteLine("Woof!"); }
}
Run Code Online (Sandbox Code Playgroud)
然后:
Animal a = new Animal();
Animal c = new Cat();
Animal d = new Dog();
Feeder f = new Feeder();
f.Feed(a);
f.Feed(c);
f.Feed(d);
Run Code Online (Sandbox Code Playgroud)
这将打印:
i can haz cheezburger?
Meow!
Woof!
Run Code Online (Sandbox Code Playgroud)
同样,这是虚拟方法的全部要点.
此外,我们可以参考规范.从10.6.3(虚拟方法)
在虚方法调用中,进行该调用的实例的运行时类型决定了要调用的实际方法实现.
(原文中的粗体和斜体.)
准确地说,当在具有编译时类型和运行时类型(其中是或者派生自的类)的实例上使用
N参数列表调用named方法时,将按如下方式处理调用:ACRRCC•首先,过载分辨率就被应用于
C,N和A,选择一个特定的方法M从该组中声明和继承的方法C.这在§7.5.5.1中描述.•然后,如果
M是非虚方法,M则调用.• 否则,
M是一个虚方法,并且M调用关于R 的最派生实现.
(不是原来的.)
然后,我们需要定义"大多数派生的实现" M.这是一个很好的递归定义:
M关于类的虚拟方法的最派生实现R确定如下:•如果
R包含引入虚拟声明M,那么这是最衍生的实现M.•否则,如果
R包含覆盖M,则这是最派生的实现M.•否则,最派生实现
M相对于R相同派生程度最大的实现M相对于直接基类的R.
因此,在上面的示例中使用Cat : Animal和Dog : Animal,当参数ato Feeder.Feed(Animal)是Catthen 的实例时Cat.Speak是最派生的实现.这就是为什么我们会看到Meow!"而不是" i can haz cheezburger?"