在前面的文章中,咱们介绍了编译期多态、params关键字、实例化、base关键字等。本节咱们来关注另一种多态:运行时多态, 运行时多态也叫迟绑定。express
在C#语音中,运行时多态也叫方法重写(overriding),咱们能够在子类中overriding基类的同签名函数,使用“virtual & override”关键字便可。ide
建立一个console 示例工程,命名为InheritanceAndPolymorphism。在Program.cs基础上,再添加2个类文件,分别命名为ClassA.cs、ClassB.cs。拷贝以下代码:
函数
public class ClassA { public void AAA() { Console.WriteLine("ClassA AAA"); } public void BBB() { Console.WriteLine("ClassA BBB"); } public void CCC() { Console.WriteLine("ClassA CCC"); } }
ClassB:this
public class ClassB { public void AAA() { Console.WriteLine("ClassB AAA"); } public void BBB() { Console.WriteLine("ClassB BBB"); } public void CCC() { Console.WriteLine("ClassB CCC"); } }
在上面的代码中,咱们能够看到ClassA、ClassB有一样签名的方法,能够在program.cs中直接使用。lua
咱们对代码再作休整,结构以下:spa
/// <summary> /// ClassB, acting as a base class /// </summary> public class ClassB { public void AAA() { Console.WriteLine("ClassB AAA"); } public void BBB() { Console.WriteLine("ClassB BBB"); } public void CCC() { Console.WriteLine("ClassB CCC"); } } /// <summary> /// Class A, acting as a derived class /// </summary> public class ClassA : ClassB { public void AAA() { Console.WriteLine("ClassA AAA"); } public void BBB() { Console.WriteLine("ClassA BBB"); } public void CCC() { Console.WriteLine("ClassA CCC"); } }
Program.cscode
Main(= ==
F5,运行代码,结果以下:对象
ClassA AAAblog
ClassA BBB继承
ClassA CCC
ClassB AAA
ClassB BBB
ClassB CCC
ClassB AAA
ClassB BBB
ClassB CCC
但同时,在VS的Output窗口,咱们得到了3个Warnings:
'InheritanceAndPolymorphism.ClassA.AAA()' hides inherited member
'InheritanceAndPolymorphism.ClassB.AAA()'. Use the new keyword if hiding was intended.
'InheritanceAndPolymorphism.ClassA.BBB()' hides inherited member
'InheritanceAndPolymorphism.ClassB.BBB()'. Use the new keyword if hiding was intended.
'InheritanceAndPolymorphism.ClassA.CCC()' hides inherited member
'InheritanceAndPolymorphism.ClassB.CCC()'. Use the new keyword if hiding was intended.
这些Warnings的缘由是由于子类和基类的AAA、BBB、CCC方法签名相同,尽管从执行上看优先执行子类同签名的方法,可是可能会有潜在的问题,故Warnings提出。
基于上面的Warning,咱们手动修改代码,看看如何消除这些Warnings。
先给子类添加new、override关键字试试:
/// <summary> /// Class A, acting as a derived class /// </summary> public class ClassA : ClassB { public override void AAA() { Console.WriteLine("ClassA AAA"); } public new void BBB() { Console.WriteLine("ClassA BBB"); } public void CCC() { Console.WriteLine("ClassA CCC"); } }
执行的结果是报错了:
Error: 'InheritanceAndPolymorphism.ClassA.AAA()': cannot override inherited member 'InheritanceAndPolymorphism.ClassB.AAA()' because it is not marked virtual, abstract, or override
从这个错误提示信息看,咱们须要修改基类方法,如添加virtual关键字。
Main(= = =
执行,则无Warning了,经过这个实例,咱们得知经过在基类添加Virtual关键字受权其子类可override基类同签名方法的权限,方便了OOP的扩展。
在ClassA\
ClassB基础上,下面添加
ClassC,看看3个类继承关系的运行时多态:
Main(= = =
运行结果:
ClassB AAA
ClassB BBB
ClassA CCC
ClassB AAA
ClassB BBB
ClassA CCC
ClassC AAA
ClassA BBB
ClassA CCC
若是基类声明了virtual 关键字,子类可以使用
override修饰符实现运行时多态:只有在编译器动态决定是否被调用。
若是未标明virtual或非virtual,则方法是否被调用在编译期就能决定。
再看看下面的例子:
internal class A { public virtual void X() { } } internal class B : A { public new void X() { } } internal class C : B { public override void X() { } }
F5运行,结果报错了:
Error: 'InheritanceAndPolymorphism.C.X()': cannot override inherited member 'InheritanceAndPolymorphism.B.X()' because it is not marked virtual, abstract, or override
错误的缘由是A中定义了virtual的X函数,在B中用new关键字隐藏了A中的X函数。当C尝试经过override关键字的时候,是得到不了A中的virtual关键字X函数的,既在C中X函数为非Virtual的,故不能override。
Main(= =
执行结果以下:
Class: A ; Method X Class: C ; Method X
在这里,咱们经过在B类中添加new Virtual修饰符,而后在C中便可使用B中Virtual的X函数了。
在上面继承上,在运行时多态中添加第四个类:ClassD。
Main(= = ==
执行结果以下:
ClassB XXX
ClassB XXX
ClassD XXX
ClassD XXX
第一行输出中,来自a.XXX()函数 , 咱们在 ClassA中定义了XXX函数,而后在ClassB中使用new关键字切断了virtual关系--对子类而言。所以XXX函数从ClassC开始成为新的virtual函数,在这个代码中a是ClassD的实例,可是声明的为ClassA,故从下往上找,找到ClassB的XXX函数,打印并输出结果。
Main(=
运行报错:
Error: {Cannot evaluate expression because the current thread is in a stack overflow state.}
在这个例子中,((ClassA)this).XXX(); 致使了循环调用,修改成base.XXX便可修复这个强转致使的循环调用。
在C#中,子类对象可赋值给一个基类对象;相反须要强转。
override关键字用于子类重写同签名的基类virtual函数
用new和override可重写基类virtual的同签名函数
virtual修饰符的函数,只能在运行时决定是否被执行
函数未用virtual修饰,则在编译期便可决定是否被调用
原文连接:Diving in OOP (Day 3): Polymorphism and Inheritance (Dynamic Binding/Run Time Polymorphism)