3月9日 面向对象编程 多态

Profile Picture
- Published on Mar 9, 2020🌏 Public

面向对象编程 多态

对于同一种行为,可以有多种的状态和表现形式。

  1. 重载:通过不同的参数列表,实现方法名相同,但执行的代码不同。
  2. 隐藏:将父类的方法隐藏起来,用自身的同名,同参数列表的一个方法进行替换。
  3. 重写:实现直接替换掉父类方法。

隐藏跟重写,他们都能实现从子类调用时,能够实现子类的自定义方法。 两者的区别在于:

  • 隐藏: 父类继承下来的方法是没有被改动的:
    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("空");
        }
    }


}