• c# 面相对象4-多态性


    一、定义:

           多态是面向对象程序设计的又一个特性。在面向过程的程序设计中,主要工作是编写一个个的过程或函数,这些过程和函数不能重名。例如在一个应用中,需要对数值型数据进行排序,还需要对字符型数据进行排序,虽然使用的排序方法相同,但要定义两个不同的过程(过程的名称也不同)来实现。

      在面向对象程序设计中,可以利用“重名”来提高程序的抽象度和简洁性。首先我们来理解实际的现象,例如,“启动”是所有交通工具都具有的操作,但是不同的具体交通工具,其“启动”操作的具体实现是不同的,如汽车的启动是“发动机点火——启动引擎”、“启动”轮船时要“起锚”、气球飞艇的“启动”是“充气——解缆”。如果不允许这些功能使用相同的名字,就必须分别定义“汽车启动”、“轮船启动”、“气球飞艇启动”多个方法。这样一来,用户在使用时需要记忆很多名字,继承的优势就荡然无存了。为了解决这个问题,在面向对象的程序设计中引入了多态的机制。

      多态是指一个程序中同名的不同方法共存的情况。主要通过子类对父类方法的覆盖来实现多态。这样一来,不同类的对象可以响应同名的方法来完成特定的功能,但其具体的实现方法却可以不同。例如同样的加法,把两个时间加在一起和把两个整数加在一起肯定完全不同。

      通过方法覆盖,子类可以重新实现父类的某些方法,使其具有自己的特征。例如对于车类的加速方法,其子类(如赛车)中可能增加了一些新的部件来改善提高加速性能,这时可以在赛车类中覆盖父类的加速方法。覆盖隐藏了父类的方法,使子类拥有自己的具体实现,更进一步表明了与父类相比,子类所具有的特殊性。

      多态性使语言具有灵活、抽象、行为共享的优势,很好地解决了应用程序函数同名问题。

    二、实现的方法

          多态需要通过继承来实现。

    三、分类

    1、编译多态(重载overload)
     eg、 函数重载

    重载(overload):在同一个作用域(一般指一个类)的两个或多个方法函数名相同,参数列表不同的方法叫做重载,它们有三个特点(俗称两必须一可以):

    • 方法名必须相同
    • 参数列表必须不相同
    • 返回值类型可以不相同

     如: 

    1 public void Sleep()
    2         {
    3             Console.WriteLine("Animal睡觉");
    4         }
    5         public int Sleep(int time)
    6         {
    7             Console.WriteLine("Animal{0}点睡觉", time);
    8             return time;
    9         }

    2、运行多态(重写override)

    子类中为满足自己的需要来重复定义某个方法的不同实现,需要用override关键字,被重写的方法必须是虚方法,用的是virtual关键字。它的特点是(三个相同):
    • 相同的方法名
    • 相同的参数列表
    • 相同的返回值。
       1 如:父类中的定义: 
       2         public virtual void EatFood()
       3         {
       4             Console.WriteLine("Animal吃东西");
       5         } 
       6 
       7        子类中的定义:
       8 
       9         public override void EatFood()
      10         {
      11             Console.WriteLine("Cat吃东西");
      12             //base.EatFood();
      13         }

      实现方式:

      父类引用指向子类
      例子:

       1 namespace mydemo1
       2 {
       3     class Ren
       4     {
       5         public virtual void Speak()//
       6         {
       7         }
       8     }
       9 
      10     class Ghost
      11     {
      12         public void Eat(Ren e)
      13         {
      14             e.Speak();
      15             Console.WriteLine("人类真好吃!");
      16         }
      17     }
      18 
      19     class China : Ren
      20     {
      21         public override void Speak()
      22         {
      23             Console.WriteLine("汉语");
      24         }
      25     }
      26 
      27     class Usa : Ren
      28     {
      29         public override void Speak()
      30         {
      31             Console.WriteLine("English");
      32         }
      33     }
      34 
      35     class Program
      36     {
      37         public static void Main(string[] args)
      38         {
      39             Ren a = new China();//父类的引用指向子类的实例
      40             Ren b = new Usa();
      41 
      42             //a.Speak();
      43             //b.Speak();
      44 
      45             Ghost g = new Ghost();
      46             China c = new China();
      47             Usa u = new Usa();
      48 
      49             Random r = new Random();
      50             int a = r.Next(0, 3);
      51 
      52             if (a == 1)
      53             {
      54                 g.Eat(c);//改eat()方法传入的参数要求是Ren类的引用,可以向里面传其子类及父类的元素,子类对象代替父类对象
      55             }
      56             else
      57             {
      58                 g.Eat(u);
      59             }
      60             
      61 
      62         }
      63     }
      64 }

      3、虚方法

      :即为基类中定义的允许在派生类中重写的方法,使用virtual关键字定义。

      如:

      1 1  public virtual void EatFood()
      2 2         {
      3 3             Console.WriteLine("Animal吃东西");
      4 4         }

      注意虚方法也可以直接调用

      1  Animal a = new Animal();
      2             a.EatFood();

       运行结果:

    •  4、抽象方法:在基类中定义的并且必须在派生类中重写的方法,使用abstract关键字定义。如:
       1 public abstract class Biology
       2     {
       3         public abstract void Live();
       4     }
       5     public class Animal : Biology
       6     {
       7         public override void Live()
       8         {
       9             Console.WriteLine("Animal重写的抽象方法");
      10             //throw new NotImplementedException();
      11         } 
      12     }

       注意:抽象方法只能在抽象类中定义,如果不在抽象类中定义,则会报出如下错误: 

    5、里氏代换原则和抽象依赖原则

    里氏代换原则
    如果某个方法接收的是父类引用,可以向里面传父类或其子类的元素,子类对象替代父类对象
    例子:怪兽吃人

     1 class Guaishou
     2     {
     3         public void Eat(Ren r)
     4         {
     5             r.Jiao();
     6             Console.WriteLine("人类真好吃");
     7         }
     8     }
     9 
    10     class Ren
    11     {
    12         public virtual void Speak()
    13         {
    14             Console.WriteLine("说话");
    15         }
    16 
    17         public virtual void Jiao()
    18         {
    19             Console.WriteLine("55555555555555555");
    20         }
    21 
    22     }
    23 
    24     class American:Ren
    25     {
    26         public override void Speak()
    27         {
    28             Console.WriteLine("Hello");
    29         }
    30 
    31         public override void Jiao()
    32         {
    33             Console.WriteLine("SOS");
    34         }
    35     }
    36 
    37     class Chinese:Ren
    38     {
    39         public override void Speak()
    40         {
    41             Console.WriteLine("你好");
    42         }
    43         public override void Jiao()
    44         {
    45             Console.WriteLine("救命");
    46         }
    47 
    48     }
    49 
    50     class Program
    51     {
    52         static void Main(string[] args)
    53         {
    54             //Ren a = new Chinese();
    55             //a.Speak();
    56             //a = new American();
    57             //a.Speak();
    58 
    59             Guaishou g = new Guaishou();
    60 
    61             //Ren ren;
    62 
    63             Random r = new Random();
    64             int a = r.Next(0,3);
    65 
    66             if(a==1)
    67             {
    68                 American ren= new American();
    69                 g.Eat(ren);
    70             }
    71             else
    72             {
    73                Chinese  ren = new Chinese();
    74                 g.Eat(ren);
    75             }
    76 
    77 
    78         }
    79     }
    80 }

    抽象依赖原则

    用父类的引用来指向子类的实例
    例子:运行多态的例子

    6、隐藏方法在派生类中定义的和基类中的某个方法同名的方法,使用new关键字定义。

    如在基类Animal中有一方法Sleep():

    1    public void Sleep()
    2         {
    3             Console.WriteLine("Animal Sleep");
    4         }

         则在派生类Cat中定义隐藏方法的代码为:

    1 new public void Sleep()
    2         {
    3             Console.WriteLine("Cat Sleep");
    4         }

      或者为:

    1   public new void Sleep()
    2         {
    3             Console.WriteLine("Cat Sleep");
    4         }    

    注意:(1)隐藏方法不但可以隐藏基类中的虚方法,而且也可以隐藏基类中的非虚方法。

               (2)隐藏方法中父类的实例调用父类的方法,子类的实例调用子类的方法。
               (3)和上一条对比:重写方法中子类的变量调用子类重写的方法,父类的变量要看这个父类引用的是子类的实例还是本身的实例,如果引用的是父类的实例那么调用基类的方法,如果引用的是派生类的实例则调用派生类的方法。
     
    7、例题
     1 public abstract class Biology
     2     {
     3         public abstract void Live();
     4     }
     5     public class Animal : Biology
     6     {
     7         public override void Live()
     8         {
     9             Console.WriteLine("Animal重写的Live");
    10             //throw new NotImplementedException();
    11         }
    12         public void Sleep()
    13         {
    14             Console.WriteLine("Animal Sleep");
    15         }
    16         public int Sleep(int time)
    17         {
    18             Console.WriteLine("Animal在{0}点Sleep", time);
    19             return time;
    20         }
    21         public virtual void EatFood()
    22         {
    23             Console.WriteLine("Animal EatFood");
    24         }
    25     }
    26     public class Cat : Animal
    27     {
    28         public override void EatFood()
    29         {
    30             Console.WriteLine("Cat EatFood");
    31             //base.EatFood();
    32         }
    33         new public void Sleep()
    34         {
    35             Console.WriteLine("Cat Sleep");
    36         }
    37         //public new void Sleep()
    38         //{
    39         //    Console.WriteLine("Cat Sleep");
    40         //}
    41     }
    42     public class Dog : Animal
    43     {
    44         public override void EatFood()
    45         {
    46             Console.WriteLine("Dog EatFood");
    47             //base.EatFood();
    48         }
    49     }

    需要执行的代码:

    class Program
        {
            static void Main(string[] args)
            {
                //Animal的实例
                Animal a = new Animal();
                //Animal的实例,引用派生类Cat对象
                Animal ac = new Cat();
                //Animal的实例,引用派生类Dog对象
                Animal ad = new Dog();
                //Cat的实例
                Cat c = new Cat();
                //Dog的实例
                Dog d = new Dog();
                //重载
                a.Sleep();
                a.Sleep(23);
                //重写和虚方法
                a.EatFood();
                ac.EatFood();
                ad.EatFood();
                //抽象方法
                a.Live();
                //隐藏方法
                a.Sleep();
                ac.Sleep();
                c.Sleep();
                Console.ReadKey();
            }
        }
  • 相关阅读:
    【XSY1544】fixed 数学 强连通图计数
    【XSY1538】连在一起的幻想乡 数学 无向连通图计数
    拉格朗日插值
    【XSY1537】五颜六色的幻想乡 数学 生成树计数 拉格朗日插值
    【XSY1528】azelso 概率&期望DP
    【BZOJ2655】calc DP 数学 拉格朗日插值
    【XSY1529】小Q与进位制 分治 FFT
    【XSY1519】彩灯节 DP 数学 第二类斯特林数
    CODEFORCES掉RATING记 #5
    【BZOJ3992】【SDOI2015】序列统计 原根 NTT
  • 原文地址:https://www.cnblogs.com/SJP666/p/4765445.html
Copyright © 2020-2023  润新知