CH08-使用虚方法实现多态

本章目标

  1. 理解为什么要使用多态?
  2. 理解多态的概念
  3. 掌握虚方法实现多态

本章内容

1、多态概念

  1. 为什么要使用多态?

    演示案例:通过第7章讲解的继承方式来实现学生和老师的自我介绍功能。

    1. 创建父类:Person

      1
      2
      3
      4
      5
      6
      public class Person
      {
      public int Id { get; set; }
      public string Name { get; set; }
      public int Age { get; set; }
      }
    2. 创建子类(学生类和老师类),实现自我介绍方法

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      //学生类
      public class Student : Person
      {
      public string hobby { get; set; }

      public void SayHi()
      {
      Console.WriteLine("大家好,我叫:{0},年龄:{1},爱好:{2}",Name,Age,hobby);
      }
      }
      //老师类
      public class Teacher : Person
      {
      public int YearOfService { get; set; }


      public void SayHi()
      {
      Console.WriteLine("大家好,我叫:{0},年龄:{1},教龄:{2}", Name, Age, YearOfService);
      }
      }
    3. 测试类:

      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
      static void Main(string[] args)
      {
      //使用集合保存多个学生和老师对象,Person作为集合对象
      List<Person> list = new List<Person>
      {
      new Teacher(){Id=1001,Name="张老师",Age=38,YearOfService=15},
      new Student(){Id=100001,Name="张三",Age=16,hobby="篮球"},
      new Student(){Id=100002,Name="李四",Age=17,hobby="听音乐,打游戏"}
      };

      //循环集合,实现自我介绍
      foreach (Person person in list)
      {
      //通过is-a判断
      if(person is Teacher)
      {
      Teacher teacher=(Teacher)person;
      teacher.SayHi();
      }
      if(person is Student)
      {
      Student student=(Student)person;
      student.SayHi();
      }
      }
      }
    4. 通过上述代码,可思考一问题:

      在遍历Person集合实现问好功能时,需要用is关键字判段每个Person的类型。这时会带来一个问题,如果Person类的子类非常多,SayHi()方法各不相同,那么在程序中就要对众多的对象编写非常多的if语句进行判断,使程序变得庞大,扩展困难。

      如何解决以下问题?

      通过多态可以解决

  2. 多态概念:

    1. 概念:

      多态: “多种形态”,指同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果。

    2. 简单理解说明:

      多态是建立在继承的基础上,同一个方法,操作于不同的对象,实现的方式不一样,则称为多态。

    3. 生活中的多态有很多,如下:

      1. 不同对象对于同一个方法(Cut)实现不同的行为:

        1721787153815

      2. 吃饭操作:中国人吃饭用筷子,印度人吃饭用手抓,西方人吃饭用刀叉

      3. 请思考你认为生活中的多态还有那些?

  3. 在C#中实现多态的方式:

    1. 通过虚方法实现多态
    2. 通过抽象方法实现多态

2、虚方法实现多态

  1. 语法:

    1. 在父类中定义虚方法:

      1
      2
      3
      4
      访问修饰符  virtual  返回值类型  方法名() 
      {
      //方法体
      }

      注意事项:

      在方法中加入关键字:virtual

    2. 在子类中重写虚方法:

      1
      2
      3
      4
      5
      访问修饰符  override  返回值类型  方法名() 
      {
      //方法体
      }

    3. 注意事项:

      父类中定义的虚方法并非必须被子类重写。在父类中可给出虚方法的默认实现。如果子类不重写父类的虚方法,依然执行父类的默认实现;反之,则执行子类重写后的方法。

  2. 通过虚方法改善以上案例:

    1. 在父类中定义虚方法,实现自我介绍:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      public class Person
      {
      public int Id { get; set; }
      public string Name { get; set; }
      public int Age { get; set; }
      /// <summary>
      /// 在父类定义虚方法
      /// </summary>
      public virtual void SayHi()
      {
      Console.WriteLine("大家好,我叫:{0},年龄:{1}", Name, Age);
      }
      }
    2. 在子类重写父类的虚方法,通过override实现重写:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      public class Student : Person
      {
      public string hobby { get; set; }

      public override void SayHi()
      {
      Console.WriteLine("大家好,我叫:{0},年龄:{1},爱好:{2}", Name, Age, hobby);
      }
      }

      public class Teacher : Person
      {
      public int YearOfService { get; set; }

      public override void SayHi()
      {
      Console.WriteLine("大家好,我叫:{0},年龄:{1},教龄:{2}", Name, Age, YearOfService);
      }
      }
    3. 优化测试类:

      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
      static void Main(string[] args)
      {
      //使用集合保存多个学生和老师对象,Person作为集合对象
      List<Person> list = new List<Person>
      {
      new Teacher(){Id=1001,Name="张老师",Age=38,YearOfService=15},
      new Student(){Id=100001,Name="张三",Age=16,hobby="篮球"},
      new Student(){Id=100002,Name="李四",Age=17,hobby="听音乐,打游戏"}
      };

      //循环集合,实现自我介绍
      foreach (Person person in list)
      {
      /*//通过is-a判断
      if (person is Teacher)
      {
      Teacher teacher = (Teacher)person;
      teacher.SayHi();
      }
      if (person is Student)
      {
      Student student = (Student)person;
      student.SayHi();
      }*/

      person.SayHi();//直接调用父类的方法,如果子类重写了父类的虚方法,则调用子类的方法
      }
      }
  3. 虚方法实现多态注意事项:

    1. 父类定义虚方法,在方法中加入virtual关键字,子类重写虚方法使用override。
    2. 虚方法必须有方法体
    3. 子类可以重写父类的虚方法,也可以不用重写。
    4. 调用时,如果子类重写了父类的虚方法,那么直接调用子类的方法,否则,直接调用父类的虚方法。
  4. 方法重写和方法重载的区别:

    1. 方法重写:在不同的类中,方法名、参数列表、返回值一样,提供不同的实现。
    2. 方法重载:在同一个类中,方法名相同,参数不同,与返回类型无关。

本章总结

1721788545055

本章作业

  1. 通过虚方法实现多态完成学生和老师的自我介绍功能。

  2. 通过多态,实现工作汇报操作

    需求说明:

    1. PM类和SE类均继承Employee,公共属性在父类构造函数中初始化,在父类定义DoWork()虚方法
    2. 实现不同员工汇报工作的DoWork()方法,重写父类的DoWork()方法
      1. SE通过遍历工作项,输出工作信息
      2. PM输出固定工作信息

    1721788668616

  3. 多态实现计算器:

    实现思路:

    1. 创建父类Operation
      1. 属性NumberA和NumberB
      2. 虚方法GetResult()
    2. 依次创建子类OpeartionAdd等,继承父类并重写虚方法GetResult()
    3. 实现计算响应事件
      1. 根据不同运算符,创建不同子类对象
      2. 初始化运算数并执行计算

    1721788921266