一 多态的定义
同一操作作用于不同的类的实例,不同的类将进行不同的解释,最后产生不同的执行结果。
二 多态的分类
● 编译时的多态性
编译时的多态性是通过重载来实现的。对于非虚的成员来说,系统在编译时,根据传递的参数、返回的类型等信息决定实现何种操作。
● 运行时的多态性
运行时的多态性就是指直到系统运行时,才根据实际情况决定实现何种操作。c#中,运行时的多态性通过虚成员实现。
三 多态的实现方式
● 接口实现多态。
● 继承实现多态。
● 通过抽象类实现的多态。
四 多态的实现方式举例
● 接口实现多态。
/*
* 接口实现多态
* 一个公司有很多的门,但是不管什么门,都有开和关两种的状态。定义一个接口
* 定义两种类型的门door1,door2
* 公司为了验证其保安系统是否完好,检查公司2个门是否正常开和关。
*/
using System;
using System.Collections.Generic;
using System.Text;
namespace DoorApplication
{
class Program
{
static void Main(string[] args)
{
IDoor[] door = new IDoor[100];//定义一个接口数组
for(int i=1;i<=2;i++)
{
if (i % 2==0)
door[i]=new door1();
else
door[i]=new door2();
door[i].Close();//接口实现方法的访问
door[i].Open();
}
}
}
interface IDoor
{
void Open();
void Close();
}
class door1:IDoor
{
private bool HavePerson=false;
public void Open()
{
if(HavePerson)
Console.WriteLine("door1门打开了");
}
public void Close()
{
if(!HavePerson)
Console.WriteLine("door1门关上了");
}
}
class door2:IDoor
{
private bool isPassWord = false;
public void Open()
{
if (isPassWord)
Console.WriteLine("door2门打开了");
}
public void Close()
{
if (!isPassWord)
Console.WriteLine("door2门关上了");
}
}
}
输出结果:
door1门关上了
door1门打开了
door2门关上了
door2门打开了
● 继承实现多态。
/*
* 继承实现多态
* 一个公司有很多的雇员,但是不管什么雇员,都工作。定义一个基类Employee定义了虚方法StaWork()
* 经理和销售继承基类并重写了基类的虚方法StaWork(),运行时通过基类引用继承类的实例达到调用子类的方法的目的*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication2
{
public class Employee
{
protected string _name;
public Employee() { }
public Employee(string name)
{
_name = name;
}
public virtual void StaWork()//虚方法
{
Console.WriteLine(_name+"开始工作:");
}
}
class Manager : Employee
{
public Manager(string name) : base(name) { }
public override void StaWork()//从重方法
{
base.StaWork();//调用父类的StaWork方法
Console.WriteLine("给员工下达任务!");
}
}
class Seller : Employee
{
public Seller(string name) : base(name) { }
public override void StaWork()
{
base.StaWork();
Console.WriteLine("销售产品!");
}
}
class Program
{
static void Main(string[] args)
{
Employee[] emp = new Employee[3];
emp[0] = new Manager("张三");
emp[1] = new Seller("李四");
emp[2] = new Seller("王五");
Console.WriteLine("时间到了");
foreach (Employee em in emp)
{
em.StaWork();
}
}
}
}
父类的对象变量=new 子类类型,将子类对象赋值给父类对象,所得到对象是这样的一个对象,它是一个编译是为父类对象,但运行却是一个子类对象。具体特征如下:
1.被声明为父类对象
2.拥有父类属性
3.占用子类的内存空间
4.子类方法覆盖父类的方法时,此时对象调用的是子类的方法;否则,自动调用继承父类的方法.
5.我人认为这个对象既不是父类对象,也不是子类对象.当我们用到它的方法时,
我便把它看成子类对象;若用到它的属性时,我把它看成父类对象.它是一个占用父类属性,而使用子类方法的对象.至于到底是什么对象,我认为还是得根据声明来,它应算是父类对象,但拥有子类方法.
● 通过抽象类实现多态。
抽象类同时提供继承和接口的元素。抽象类本身不能实例化,他必须被继承。该类的部分或全部成员可能未实现,该实现由继承类提供。已实现的成员仍可被重写,并且继承类仍能实现附加接口或其他功能。抽象类提供继承和接口实现的功能。抽象类不能示例化,必须在继承类中实现。他能包含已实现的方法和属性,但也能包含未实现的过程,这些未实现过程必须在继承类中实现。这使你得以在类的某些方法中提供不变级功能,同时为其他过程保持灵活性选项打开。抽象类的另一个好处是:当需求组件的新版本时,可根据需要将附加方法添加到基类,但接口必须保持不变。
/*定义一个抽象类VideoShow及其抽象方法 playVideo在定义两个DVD,VCD类继承并重写playVideo方法
*然后利用抽象类playVideo引用DVD,VCD类实例来调用DVD,VCD类地方法达到多态的效果。
*/
using System;
using System.Collections.Generic;
using System.Text;
namespace Video
{
class Program
{
static void Main(string[] args)
{
Program p = new Program();
p.PlayVideo();
}
public void PlayVideo()
{
VideoShow vw;
vw = new DVD();
Console.WriteLine(vw.playVideo());
vw = new VCD();
Console.WriteLine(vw.playVideo());
}
}
public abstract class VideoShow //不能被实例化
{
public abstract string playVideo();
}
public class VCD:VideoShow
{
public override string playVideo()
{
return "正在播放VCD";
}
}
public class DVD : VideoShow
{
public override string playVideo()
{
return "正在播放DVD";
}
}
}
既然抽象类不能实例化,那么这段代码为什么又可以运行呢?首先要明确上面的代码并没有实例化抽象类,只是声明了一个抽象类的对象,实例化时必须通过构造函数来实现,这里调用的是子类的构造函数,所以实例化的是子类对象,只是抽象类对象引用了子类实例。
抽象类的派生类必须实现所有的抽象方法,必须使用override关键字,并且不能是私有的。
五 总结
面向对象程式设计中的另外一个重要概念是多态性。在运行时,能通过指向基类的指针,来调用实现派生类中的方法。能把一组对象放到一个数组中,然后调用他们的方法,在这种场合下,多态性作用就体现出来了,这些对象不必是相同类型的对象。当然,如果他们都继承自某个类,你能把这些派生类,都放到一个数组中。如果这些对象都有同名方法,就能调用每个对象的同名方法。