前一篇隐藏的实例中,由于子类隐藏了父类的同名方法,如果不进行强制转换,就无法通过父类变量直接调用子类的同名方法,哪怕父类变量引用的是子类变量。
我们希望的是每个对象“各司其职”。
为了达到这个目的,可以在父类同名方法前加关键字virtual,表明这是一个虚方法,子类可以重写此方法:即在子类同名方法前加关键字override,表明这是对父类同名方法进行了重写。
请看如下代码:
1 class Parent //父类 2 { 3 public virtual void OverrideF() //父类的虚方法方法 4 { 5 System.Console.WriteLine("Parent.OverrideF()"); 6 } 7 } 8 class Child : Parent //子类继承父类 9 { 10 public override void OverrideF()//子类的重写方法 11 { 12 System.Console.WriteLine("Child.OverrideF()"); 13 } 14 }
请看一下使用代码(在主函数中调用):
1 Child c = new Child(); 2 Parent p; 3 p = c; 4 p.OverrideF();//调用父类的还是子类的同名方法?
上述代码运行的结果:
这一事例表明,将父类方法定义为虚方法,子类重写同名方法之后,通过父类变量调用此方法,到底是调用父类还是子类的,由父类变量引用的真实对象类型决定,而与父类变量无关。
换句话说,同样一句代码:
p.OverrideF();
在p引用不同对象时,其运行的结果完全不一样!因此,如果我们再编程时只针对父类变量提供的对外接口编程,就是我们的代码成了“变色龙”,传给它不同的子类对象(这些子类对象都重写了父类的同名方法),它就会做不同的事。这就是面向对象语言中的“虚方法调用”特性。这一特性会让我们写出非常灵活的代码,大大减少由于系统功能扩充和改变带来的大量代码修改工作量。
结论:
面向对象怨言拥有的“虚方法调用”特性,使我们可以只用同样的一个语句,在运行时根据对象类型而执行不同的操作。