一、概述
同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果,这就是多态性。
可以用不同的方式实现组件中的多态性:
● 接口多态性。
● 继承多态性。
● 通过抽象类实现的多态性。
二、实现
2.1、虚方法
定义:当类中的方法声明前加上 virtual 修饰符,则称之为虚方法。
作用:子类可以对父类中的虚方法进行重写,虚方法是多态特性的一种体现。
即,用virtual关键字修饰父类方法,用 override 关键字修饰子类方法,实现了方法重写。
特点:
a)、使用了virtual修饰符后不允许再有static、abstract或override修饰符
b)、父类方法的访问级别和子类重写方法的的访问级别必须相同,即它们应该具有相同的访问修饰符
2.2、抽象类和抽象方法
描述:如果一个类不与具体的事物相联系,而只是表达一种抽象的概念,仅仅是作为其派生类的一个基类,这样的类就是抽象类,在抽象类中声明方法时,如果加上abstract时就是抽象方法。
抽象类是特殊的类,只是不能被实例化;除此以外,具有类的其他特性;重要的是抽象类可以包括抽象方法,这是普通类所不能的。
抽象方法只能声明于抽象类中,且不包含任何实现,派生类必须覆盖它们。另外,抽象类可以派生自一个抽象类,可以覆盖基类的抽象方法也可以不覆盖,如果不覆盖,则其派生类必须覆盖它们。
2.2.1、抽象类的特点:
a)、抽象类不能实例化(不能使用new 操作)
b)、抽象类可以包含抽象方法和抽象访问器
c)、抽象类不能是密封的或静态的(不能在抽象类前加 static 或 sealed)
d)、从抽象类派生的非抽象类必须实现继承的所有抽象方法和抽象访问器
e)、抽象类是子类的描述,只有被子类继承,才有实际意义
2.2.2、抽象类对构造函数的限制:
a)、不要在抽象类中定义公共的或受保护的内部构造函数(具有public或protected internal可见性的构造函数用于能进行实例化的类型,而任何情况下抽象类型不能实例化)
b)、应在抽象类中定义一个受保护的(protected)或私有的(private)构造函数
c)、如果在抽象类中定义一个受保护的(protected)构造函数,则在创建派生类的实例时,基类可执行初始化。
2.2.3、抽象方法的特点:
定义:在抽象类中,一个方法声明如果加上 abstract 修饰符,则称该方法为抽象方法
a)、抽象方法是隐式的虚方法。(抽象方法可以看作是没有方法体的虚方法)
b)、只允许在抽象类中使用抽象方法声明
c)、因为抽象方法声明不提供实际的实现,所有没有方法体。(即:方法声明只是以一个分号结束,并且在签名后没有大括号{},实现由重写方法提供,此重写方法是非抽象类的成员)
d)、在抽象方法声明中不能使用 static 或 virtual 修饰符
e)、除了在声明和调用语法上不同外,抽象属性的行为与抽象方法一样
f)、不能在静态属性上使用 abstract 修饰符
g)、在派生类中,通过包括使用 override 修饰符的属性声明,可以重写抽象的继承属性
[注]:
Animal a = new Dog;
a.Cry();
a.Show;
Animal:抽象类,其中有一个抽象方法Cry(),一个具体方法Show()
Dog:继承父类Animal,并使用 override 重写抽象方法Cry(),并且有一个子类自己的具体方法ShowDog()
由此可得结论:
1、并没有实例化抽象类,只是声明了一个抽象类对象,实例化必须通过构造函数来实现,而这里调用的是子类的构造函数,所以实例化的是子类对象,只是抽象对象引用了子类实例
2、抽象类对象调用了子类的Cry()方法和本身的Show方法,子类的ShowDog()方法是不能被访问的
3、抽象类对象引用子类实例后,基本上还是属于抽象类,能够访问子类重写的方法和父类自己的属性和方法,子类自己的属性和方法是不能访问的。
2.3、接口
描述:
a)、在.NET中,接口是一种规范和标准,是纯粹的协议。
b)、接口没有提供默认的实现,由接口定义的某个特定成员依赖于它所模拟的确切行为。接口表示某个类或结构可以选择去实现的行为。
c)、从语法来说,接口使用 interface 关键字定义。和类不一样的是,接口不指定基类,但接口可以指定基接口。
d)、接口的成员不指定访问修饰符(因为所有接口成员都是隐式公共的和抽象的)
e)、除非被类或接口实现,否则接口没有作用。
f)、直接基类必须是冒号操作符后的第一个项。
g)、实现接口是一个“要么全要,要么全不要”的命题。
h)、当一个类继承某个接口时,它不仅要实现该接口定义的所有方法,还要实现该接口从其他接口中继承的所有方法。
i)、在C#中,一个类虽然不能实现多重继承,但是一个类可以实现多个接口。
j)、接口是引用类型的,类似于类。
k)、 接口基本上不具备继承的任何具体特点,它仅仅承诺了能够调用的方法;
l)、 一个类一次可以实现若干个接口,但是只能扩展一个父类。
m)、好的接口定义应该是具有专一功能性的,而不是多功能的,否则造成接口污染。如果一个类只是实现了这个接口的中一个功能,而不得不去实现接口中的其他方法,就叫接口污染。
2.4、区别
2.4.1、抽象方法和虚方法的区别:
1>虚方法有实现部分,并为派生类提供了覆盖该方法的选项,抽象方法则没有提供实现部分,强制派生类覆盖该方法
2>abstract方法只能在抽象类中声明,virtual方法则不是
3>abstract方法必须在派生类中重写,virtual方法则不必
4>abstract方法不能声明方法体,virtual方法则可以
5>包含abstract方法的类不能被实例化,而包含virtual方法的类则可以
2.4.2、接口和抽象类的区别:
相同点:
1>都不能被直接实例化,都可以通过继承实现其方法
2>包含未实现的方法声明
不同点:
1>接口支持多重继承;抽象类不能实现多重继承。
2>接口只能定义抽象规则,抽象类既可以定义规则,还可以提供已实现的成员。
3>接口是一组行为规范;抽象类是一个不完全的类。
4>接口可以用于支持回调;抽象类不能实现回调,因为继承不支持。
5>接口可以作用于值类型和引用类型;抽象类只能作用于引用类型。(例如,struct就可以继承接口,而不能继承类)
6>抽象类实现的具体方法默认为虚的,但实现接口的类中的接口方法却默认为非虚的,当然您也可以声明为虚的。
7>抽象类实现了oop中的一个原则,把可变的与不可变的分离。抽象类和接口就是定义为不可变的,而把可变的作为子类去实现。
8>微软的自定义接口总是后带able字段,证明其是表述一类类“我能做。。。”。抽象类更多的是定义在一系列紧密相关的类间,而接口大多数是关系疏松但都实现某一功能的类中。
9>(接口)与非抽象类类似,抽象类也必须为在该类的基类列表中列出的接口的所有成员提供它自己的实现。但是,允许抽象类将接口方法映射到抽象方法上。
10>如果抽象类实现接口,则可以把接口中方法映射到抽象类中作为抽象方法而不必实现,而在抽象类的子类中实现接口中方法。
2.4.3、抽象类和接口的使用:
1.如果预计会出现版本问题,可以创建“抽象类”。
2.“接口不变”,是应该考虑的重要因素。所以,在由接口增加扩展时,应该增加新的接口,而不是更改现有接口。
3.抽象类主要用于关系密切的对象;而接口适合为不相关的类提供通用功能。
4.接口多定义对象的行为;抽象类多定义对象的属性。
5.尽量将接口设计成功能单一的功能块,以.NET Framework为例,IDisposable、IComparable等都只包含一个公共方法。
作者:陌轩君
出处:http://www.cnblogs.com/yuan-jun/p/6413211.html
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。