-多态:(转自CSND)
通过继承,一个类可以用作多种类型:可以用作它自己的类型、任何基类型,或者在实现接口时用作任何接口类型。这称为多态性。C# 中的每种类型都是多态的。类型可用作它们自己的类型或用作 Object 实例,因为任何类型都自动将 Object当作基类型。
多态性不仅对派生类很重要,对基类也很重要。任何情况下,使用基类实际上都可能是在使用已强制转换为基类类型的派生类对象。基类的设计者可以预测到其基类中可能会在派生类中发生更改的方面。例如,表示汽车的基类可能包含这样的行为:当考虑的汽车为小型货车或敞篷汽车时,这些行为将会改变。基类可以将这些类成员标记为虚拟的,从而允许表示敞篷汽车和小型货车的派生类重写该行为。
-虚方法(virtual):
子类可以对父类中的虚方法进行重写,虚方法是多态特性的一种体现
实例说明:
在不使用多态和虚方法的情况下,我们去尝试编写一段代码:
首先定义三个类,Person(基类)/Chinese(派生类)/British(派生类)/Japanses(派生类),各自都继承Person类
Person,赋予3个属性 ,其余继承它的派生类都各自有自己的一个内部方法
public class Person { public string Name { get; set; } public int Age { get; set; } public string Sex { get; set; } }
public class Chinese : Person { public void Show() { Console.WriteLine("我是中国人"); } }
public class British : Person { public void Show() { Console.WriteLine("我是英国人"); } }
public class JaPanese : Person { public void Show() { Console.WriteLine("我是日本人"); } }
这时候我们根据以上来完成实例化对象后,让它们能分别调用自己的内部方法,代码是这样的:
class Program { static void Main(string[] args) { Person[] people = new Person[5]; Chinese cn1 = new Chinese(); Chinese cn2 = new Chinese(); British br1 = new British(); British br2 = new British(); JaPanese jp1 = new JaPanese(); people[0] = cn1; people[1] = cn2; people[2] = br1; people[3] = br2; people[4] = jp1; for (int i = 0; i < people.Length; i++) { if (people[i] is Chinese) { Chinese cn = (Chinese)people[i]; cn.Show(); } else if (people[i] is British) { British b = (British)people[i]; b.Show(); } else if (people[i] is JaPanese) { JaPanese j = (JaPanese)people[i]; j.Show(); } } Console.ReadKey(); }
从以上代码来看,Person类型中没有Show方法所以无法直接通过Person类型来调用Show()方法。
这一段代码看起来很糟糕,首先扩展性非常不好,而且完全违背开放封闭原则。假设未来功能中要多加1个派生类,那源代码也要跟着多加一个else if的判断。可问题是如果要加N个了!那岂能忍?那这个时候就必须得祭出大招了……我们尝试运用虚方法和多态来改善这一段代码。
首先在Person类中添加一个Show()方法,并且将父类中的Show()方法返回类型标记为virtual(虚方法)
public class Person { public string Name { get; set; } public int Age { get; set; } public string Sex { get; set; } public virtual void Show() { } }
在其余派生类中将原有的Show方法标记为override,直接对父类中的Show()方法进行重写
(其余2个类变动都相同,这里就不再重复了)
public class Chinese : Person { public override void Show() { Console.WriteLine("我是中国人"); } }
最后我们再来改动调用时的代码
for (int i = 0; i < people.Length; i++) { //因为Person类型中没有Show方法所以无法直接通过Person类型调用Show()方法 //people[i].Show(); //Chinese cn = (Chinese)people[i]; //cn.Show(); #region 判断对象类型,进行转换,然后调用不同的方法 //if (people[i] is Chinese) //{ // Chinese cn = (Chinese)people[i]; // cn.Show(); //} //else if (people[i] is British) //{ // British b = (British)people[i]; // b.Show(); //} //else if (people[i] is JaPanese) //{ // JaPanese j = (JaPanese)people[i]; // j.Show(); //} #endregion //这句话提现了多态 people[i].Show(); }
这样,我们就只需要直接调用Person里的Show()方法,而不再去考虑[i]的类型是哪一个。未来如果业务需要多加,直接多加一个派生类,然后继承Person就可以了。不需要再去变更源代码
总结:
虚方法的特点:
1.在父类中把需要设置为虚方法的方法前加vitural标记。
2.虚方法在父类中必须有实现
public virtual void Show() { //Console.WriteLine("Person 中的Show方法."); }
3.子类继承父类后,可以选择对虚方法进行重写也可以选择不重写。
4.当子类重写父类中的方法的时候,必须保证重写后的方法与原方法的返回值类型、方法名、参数列表完全一致。
5.当方法的标记是virtual或者override的时候可以重写。
class SDR:Person { override void Show() { Console.WriteLine("I'm s d r"); } } class PJR : SDR { override void Show() { Console.WriteLine("I'm p j r"); } }