3月9日 面向对象编程 多态
面向对象编程 多态
对于同一种行为,可以有多种的状态和表现形式。
- 重载:通过不同的参数列表,实现方法名相同,但执行的代码不同。
- 隐藏:将父类的方法隐藏起来,用自身的同名,同参数列表的一个方法进行替换。
- 重写:实现直接替换掉父类方法。
隐藏跟重写,他们都能实现从子类调用时,能够实现子类的自定义方法。 两者的区别在于:
- 隐藏: 父类继承下来的方法是没有被改动的:
Child a=new Child();
Parent b=a;
b.Eat(); //父类的Eat方法
a.Eat(); //子类的Eat方法
class Program{
static void Main()
{
var cat= new Cat();
Animal ani = cat;
cat.Eat(); //子类的代码
ani.Eat(); //吃东西
}
}
public class Cat: Animal
{
public new void Eat()
{
Console.WriteLine("子类的代码");
Console.ReadKey();
}
}
public class Animal{
public void Eat()
{
Console.WriteLine("吃东西");
Console.ReadKey();
}
}
- 重写: 无论从父类还是子类去调用子类方法,结果都相同:
Child a=new Child();
Parent b=a;
b.Eat(); //子类的Eat方法
a.Eat(); //子类的Eat方法
public class Program{
static void Main()
{
var cat= new Cat();
Animal ani = cat;
cat.Eat(); //子类的代码
ani.Eat(); //子类的代码
}
}
public class Cat: Animal
{
public override void Eat()
{
Console.WriteLine("子类的代码");
Console.ReadKey();
}
}
public class Animal{
public virtual void Eat()
{
Console.WriteLine("吃东西");
Console.ReadKey();
}
}
项目中,绝大多数数情况,使用的都是重写的方式,他的优势在于,以父类型进行存储时,不需要判断转化为子类型,就可以调用子类型的处理逻辑。
要实现隐藏跟重写,一定要在继承的基础上才能做。
多态,可以提高程序的扩展性和灵活性。
练习:
Animal父类下面定义三个子类型,分别是Cat/Dog/Mouse,表示各种动物,动物会以不同的声音叫(Talk)
1. 添加动物
2. 逐个叫
using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
namespace Test4
{
class Program
{
static void Main()
{
ShowMenu();
}
/// <summary>
/// 显示菜单
/// </summary>
private static void ShowMenu()
{
Console.Clear();
Console.WriteLine("1. 添加动物\n2. 叫");
var key = Console.ReadKey();
switch (key.KeyChar)
{
case '1':
AddAnimal();
break;
case '2':
EveryoneTalk();
break;
}
}
private static List<Animal> list=new List<Animal>();
/// <summary>
/// 叫
/// </summary>
private static void EveryoneTalk()
{
foreach (Animal item in list)
{
item.Talk();
}
Console.WriteLine("按任意键继续");
Console.ReadKey();
ShowMenu();
}
/// <summary>
/// 添加动物
/// </summary>
private static void AddAnimal()
{
Console.WriteLine("\n1. 狗\n2. 猫\n3. 老鼠");
var key = Console.ReadKey();
switch (key.KeyChar)
{
case '1':
list.Add(new Dog());
break;
case '2':
list.Add(new Cat());
break;
case '3':
list.Add(new Mouse());
break;
default:
AddAnimal();
break;
}
Console.WriteLine("\n添加成功,按任意键继续");
Console.ReadKey();
ShowMenu();
}
public class Cat : Animal
{
public override void Talk()
{
Console.WriteLine("喵喵喵");
}
}
public class Dog : Animal
{
public override void Talk()
{
Console.WriteLine("汪汪汪");
}
}
public class Mouse : Animal
{
public override void Talk()
{
Console.WriteLine("吱吱吱");
}
}
public class Animal
{
public virtual void Talk() {
}
}
}
}
继承从各个类去的调用结果
不需要去关心是从什么类型去调用的,只需要关心new的实例对应的类,到被继承的virtual方法所在类之间的整个继承链上,最后重写这个virtual方法的是谁。从该继承链上,无论哪个类进行调用,执行的结果都是最后重写的那个执行的结果。
using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
namespace Test4
{
class Program
{
static void Main()
{
var boshi = new BoShiMao();
boshi.Talk();//BoShiMao
((Cat)boshi).Talk(); //BoShiMao
((Animal)boshi).Talk(); //BoShiMao
Console.ReadKey();
}
}
public class BoShiMao : Cat
{
public override void Talk()
{
Console.WriteLine("BoShiMao");
}
}
public class Cat : Animal
{
public override void Talk()
{
Console.WriteLine("Cat");
}
}
public class Animal
{
public virtual void Talk() {
}
}
}
隐藏的方式,从各个类去调用的结果
只需要关心调用的类型下面有没有new要调用的方法,如果有就调用自己的,没有的话,会往继承链逐层往上找,找到最近一层new的方法,如果找到基类还没有找到new的方法,就会执行基类的对应方法,这时候,就要注意基类在哪里被重写了。
using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
namespace Test4
{
class Program
{
static void Main()
{
var boshi = new BoShiMao();
boshi.Talk();//BoShiMao
((Cat)boshi).Talk(); //Cat
((Animal)boshi).Talk(); //空
Console.ReadKey();
}
}
public class BoShiMao : Cat
{
public new void Talk()
{
Console.WriteLine("BoShiMao");
}
}
public class Cat : Animal
{
public new void Talk()
{
Console.WriteLine("Cat");
}
}
public class Animal
{
public virtual void Talk() {
Console.WriteLine("空");
}
}
}