CS3L18——多态vob
本章代码关键字
多态
多态就是按字面的意思就是“多种状态”,让继承同一父类的子类们,在执行相同方法是有不同的表现
主要目的:同一父类的对象 执行相同行为(方法)有不同的表现
多态要解决的问题:让同一个对象有唯一行为的特征
以前没有学习多态相关关键字时,要在子类重写一个父类方法需要使用 new
关键字
但是 new
关键字在 里氏替换情况下,会出现问题,例如下面的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 class Father { public void SpeakName () { Console.WriteLine("Father的方法" ); } } class Son : Father { public new void SpeakName () { Console.WriteLine("Son的方法" ); } } internal class Program { static void Main (string [] args ) { Father f = new Son(); f.SpeakName(); (f as Son).SpeakName(); } }
输出:
可见,当使用父类装载子类时,调用子类通过 new
覆盖的方法还是会调用父类的方法
虽然用 as
可以解决这个执行父类方法的问题,但是这样就破坏了对象的唯一性,因为一个对象可以使用两种类的方法了
这也让里氏替换失去意义,因为我们还是要知道子类具体是什么类型才能执行子类方法
多态的实现
我们目前已经学过的多态:编译时多态 —— 函数重载,开始就写好的
我们将学习的:运行时多态(vob、抽象函数、接口),这次是vob
v: virtual
(虚函数)
o: override
(重写)
b: base
(父类)
父类里使用 virtual
修饰的方法,在子类里可以通过 override
去重写,子类重写的方法可以通过 base
来调用父类的方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 class GameObject { public string name; public GameObject (string name ) { this .name = name; } public virtual void Atk () { Console.WriteLine("游戏对象进行攻击" ); } } class Player : GameObject { public Player (string name ) : base (name ) { } public override void Atk () { base .Atk(); WriteLine("玩家对象进行攻击" ); } } class Monster : GameObject { public Monster (string name ) : base (name ) { } public override void Atk () { WriteLine("怪物对象进行攻击" ); } } internal class Program { static void Main (string [] args ) { GameObject p = new Player("MrTang" ); p.Atk(); GameObject m = new Monster("monster" ); m.Atk(); } }
输出:
1 2 3 游戏对象进行攻击 玩家对象进行攻击 怪物对象进行攻击
可以看见,vob就可以彻底的覆盖父类的方法,保证了同一个对象有唯一行为的特征
里氏替换原则的意义也在这里体现,在函数传递时,可以将使用基类的参数,外部传入子类对象,
在函数内部不需要关心这个基类继承了什么子类,我们只需要调用父类声明好的方法,就可以调用子类的方法
例如一个拥有 Atk
行为的 GameObject
,外部可以传入各种各样的基于 GameObject
派生的对象,
尽管它们有不同的实现,成员也可能不同,但它们派生自 GameObject
,就一定有 Atk
行为,
因此函数内部也只需要调用 Atk
行为即可,而无需知道它是什么类型
下面的 ObjectAtk
函数就可以接受派生自 GameObject
各种参数,而不需要在意参数具体是什么类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 class GameObject { public virtual void Atk () { Console.WriteLine("游戏对象进行攻击" ); } } class Player : GameObject { public override void Atk () { WriteLine("玩家对象进行攻击" ); } } class Monster : GameObject { public override void Atk () { WriteLine("怪物对象进行攻击" ); } } internal class Program { static void Main (string [] args ) { Player p = new Player("MrTang" ); Monster m = new Monster("monster" ); ObjectAtk(p); ObjectAtk(m); } static void ObjectAtk (GameObject obj ) { obj.Atk(); } }
输出: