【C#学习记录】七、面向对象概念3(多态)

多态专题

多态的概念

让一个对象能够表现出多种的状态(类型),屏蔽各个子类对象的差异

应用场景:

using 多态学习;
Chinese cn1 = new Chinese("徐");
Chinese cn2 = new Chinese("徐");
Japanese jp = new Japanese("仓");
Korea kr = new Korea("贤");
Person[] pers = { cn1,cn2,jp,kr};
for (int i = 0; i < pers.Length; i++)
{
    //pers[i].SayHello();
    if (pers[i] is Chinese)
    {
        ((Chinese)pers[i]).SayHello();
    }
    else if (pers[i] is Japanese)
    {
        ((Japanese)pers[i]).SayHello();
    }
    else if (pers[i] is Korea)
    {
        ((Korea)pers[i]).SayHello();
    }
    else
    {
        pers[i].SayHello();
    }
}
Console.ReadKey();

在上面的程序中,希望这一段强转,只用pers[i].SayHello();这一句实现,此时就需要用到多态。
实现多态的三种方法:

  1. 虚方法
  2. 抽象类
  3. 接口

虚方法实现多态

步骤:
将父类的方法标记为虚方法,标记为virtual,这个函数在子类可以重新写一遍,使用override。
例子:经理十一点打卡,员工九点打卡,程序员不打卡

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Program
{
public void Main(string arg[])
{
	YuanGong yg = new YuanGong();
	JingLi jl = new JingLi();
	ChengXuYu an cxy = new ChengXuYuan();
	YuanGong[] dakayun = {yg,jl,cxy};
	for(int i = 0;i<3;i++)
	{
		YuanGong[i].daka();
	}
}

public class YuanGong
{
	public virtual void daka()
	{
		Console.WriteLine("九点打卡");
	}
}

public class JingLi
{
	public override void daka()
	{
		Console.WriteLine("经理十一点打卡");
	}
}

public class ChengXuYuan
{
	public override void daka()
	{
		Console.WriteLine("程序员不打卡");
	}
}
}

抽象类实现多态

当父类中的方法不知道如何去实现的时候,可以考虑将父类写成抽象类,将子类写成抽象方法。
例如:狗狗会叫,猫咪会叫
这个例子中,狗狗和猫咪不能互为继承关系,此时需要抽象出来一个动物类,但是动物类中,并不知道叫Bark()函数如何实现,这种情况下,用抽象类实现多态。
抽象类,父类中用abstract修饰词,没有方法体,子类中还是用override。

	public abstract class Animals
	{
		public abstract void Bark();
	}
	public class Cats:Animals
	{
		public override void Bark()
		{
			Console.WriteLine("狗狗叫");
		}
	}
	public class Dogs:Animals
	{
		public override void Bark()
		{
			Console.WriteLine("猫猫叫");
		}
	}
	public void Main(string arg[])
	{
		Animals a = new Dogs();
		a.Bark();
	}

这里定义了一个Dogs类型的对象,但是转换成了父类Animals类,这里.Bark()函数表现的还是Animals类里面的,但是执行的是子类中的函数,具体执行哪一个函数,看这个对象里面装的是哪一个子类。
抽象成员的特点:

  1. 抽象成员必须标记为abstract,并且不能有任何实现。
  2. 抽象成员必须在抽象类中
  3. 抽象类不能被实例化
  4. 子类继承抽象类后,必须把父类中的所有抽象成员都重写(除非子类也是一个抽象类,则可以不重写)
  5. 抽象成员的访问修饰符不能是private
  6. 在抽象类中可以包含实例成员。并且抽象类的实例成员可以不被子类实现。
  7. 抽象类是有构造函数的。虽然不能被实例化。
  8. 如果父类的抽象方法中有参数,那么,继承这个抽象父类的子类在重写父类的方法的时候必须传入对应的参数。如果抽象父类的抽象方法中有返回值,那么子类在重写这个抽象方法的时候,也必须要传入返回值。

如果父类中的方法有默认的实现,并且父类需要被实例化,这是可以考虑将父类定义成一个普通类,用虚方法来实现多态。
如果父类中的方法没有默认实现,父类也不需要被实例化,则可以将该类定义成抽象类。

接口实现多态

接口的概念

接口就是一个规范、能力。

[public] Interface I...able
{
    成员;
}

接口中的成员不允许添加访问修饰符,默认就是public,不能修改

接口中不允许写具有方法体的函数

为了多态,接口不能被实例化。也就是说,接口不能new(不能创建对象)

(默认为public)接口中的成员不能有任何实现(“光说不做”,只是定义了一组未实现的成员)

接口中只能有方法、属性、索引器、事件不能有“字段”和构造函数

接口和接口之间可以继承,并且可以多继承

接口并不能去继承一个类,而类可以继承接口(接口只能继承于接口,而类既可以继承接口,也可以继承类)

实现接口的子类必须实现该接口的全部成员

一个类可以同时继承一个类并实现多个接口,如果一个子类同时继承了父类A,并实现了接口IA,那么语法上A必须卸载IA的前面

*当一个抽象类实现接口的时候,需要子类去实现接口。

显式实现接口

显式实现接口的目的,解决方法的重名问题。

什么时候显式的去实现接口

当继承的接口中的方法和参数一模一样的时候,要用显式的实现接口

在继承接口的类中,可以定义自己的函数以及接口的函数

        public void Fly()
        {
            Console.WriteLine("人类会飞");
        }
        void IFlyable.Fly()
        {
            Console.WriteLine("接口的飞");
        }

根据定义类型的不同,引用的函数是不同的。

IFlyable per1 = new Person("徐");
Person per2 = new Person("徐");
per1.Fly();
per2.Fly();

多态的练习

使用多态求矩形的面积和周长以及圆形的面积和周长

模仿U盘、硬盘、MP3插入电脑进行读写

Computer类:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace 存储设备读写
{
    internal class Computer
    {
        private Storage _ms;

        internal Storage Ms { get => _ms; set => _ms = value; }
        public void CpuRead()
        {
            Ms.Read();
        }
        public void CpuWrite()
        {
            Ms.Write();
        }
    }
}

Storage类:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace 存储设备读写
{
    internal abstract class Storage
    {
        public abstract void Read();
        public abstract void Write();
    }
}

HardDisk类:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace 存储设备读写
{
    internal class HardDisk : Storage
    {
        public override void Read()
        {
            Console.WriteLine("正在读HardDisk");
        }

        public override void Write()
        {
            Console.WriteLine("正在写HardDisk");
        }
    }
}

Udisk类:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace 存储设备读写
{
    internal class Udisk:Storage
    {
        public override void Read()
        {
            Console.WriteLine("正在读Udisk");
        }
        public override void Write()
        {
            Console.WriteLine("正在写Udisk");
        }
    }
}

MP3类:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace 存储设备读写
{
    internal class MP3 : Storage
    {
        public override void Read()
        {
            Console.WriteLine("正在读MP3");
        }

        public override void Write()
        {
            Console.WriteLine("正在写MP3");
        }
        public void PlayMusic()
        {
            Console.WriteLine("正在播放音乐");
        }
    }
}

Main函数:

using 存储设备读写;

Storage storage = new HardDisk();//MP3();
Computer computer = new Computer();
computer.Ms = storage;
computer.CpuRead();
computer.CpuWrite();

多态总结

实现方法 什么时候
虚方法 能够抽象出一个父类,必须得写上这些子类共同的实现的方法
抽象类 能够抽象出一个父类,但是写不出具体的实现方法
接口 找不出来父类,但是有共同的能力
posted @ 2022-03-08 15:16  翻兽  阅读(70)  评论(0)    收藏  举报