多态性
2015-10-20 17:16
141 查看
多态性常被视为自封装和继承之后,面向对象的编程的第三个支柱。 Polymorphism(多态性)是一个希腊词,指“多种形态”,多态性具有两个截然不同的方面:
• 在运行时,在方法参数和集合或数组等位置,派生类的对象可以作为基类的对象处理。 发生此情况时,该对象的声明类型不再与运行时类型相同。
• 基类可以定义并实现虚方法,派生类可以重写这些方法,即派生类提供自己的定义和实现。 在运行时,客户端代码调用该方法,CLR 查找对象的运行时类型,并调用虚方法的重写方法。 因此,你可以在源代码中调用基类的方法,但执行该方法的派生类版本。
虚方法允许你以统一方式处理多组相关的对象。 例如,假定你有一个绘图应用程序,允许用户在绘图图面上创建各种形状。 你在编译时不知道用户将创建哪些特定类型的形状。 但应用程序必须跟踪创建的所有类型的形状,并且必须更新这些形状以响应用户鼠标操作。 你可以使用多态性通过两个基本步骤解决这一问题:
1. 创建一个类层次结构,其中每个特定形状类均派生自一个公共基类。
2. 使用虚方法通过对基类方法的单个调用来调用任何派生类上的相应方法。
首先,创建一个名为 Shape 的基类,并创建一些派生类,例如 Rectangle、Circle 和 Triangle。 为 Shape 类提供一个名为 Draw 的虚方法,并在每个派生类中重写该方法以绘制该类表示的特定形状。 创建一个 List 对象,并向该对象添加 Circle、Triangle 和 Rectangle。 若要更新绘图图面,请使用 foreach 循环对该列表进行循环访问,并对其中的每个 Shape 对象调用 Draw 方法。 虽然列表中的每个对象都具有声明类型 Shape,但调用的将是运行时类型(该方法在每个派生类中的重写版本)。
多态性概述 虚成员
当派生类从基类继承时,它会获得基类的所有方法、字段、属性和事件。 派生类的设计器可以选择是否
• 重写基类中的虚拟成员。
• 继承最接近的基类方法而不重写它
• 定义隐藏基类实现的成员的新非虚实现
仅当基类成员声明为 virtual 或 abstract 时,派生类才能重写基类成员。 派生成员必须使用 override 关键字显式指示该方法将参与虚调用
使用新成员隐藏基类成员
如果希望派生成员具有与基类中的成员相同的名称,但又不希望派生成员参与虚调用,则可以使用 new 关键字。new 关键字放置在要替换的类成员的返回类型之前。
阻止派生类重写虚函数
无论在虚拟成员和最初声明虚拟成员的类之间已声明了多少个类,虚拟成员永远都是虚拟的。 如果类 A 声明了一个虚拟成员,类 B 从 A 派生,类 C 从类 B 派生,则类 C 继承该虚拟成员,并且可以选择重写它,而不管类 B 是否为该成员声明了重写。派生类可以通过将重写声明为 sealed 来停止虚拟继承。 这需要在类成员声明中的 override 关键字前面放置 sealed关键字。通过使用 new 关键字,密封的方法可以由派生类替换。已替换或重写某个方法或属性的派生类仍然可以使用基关键字访问基类的该方法或属性(base.function)。
• 在运行时,在方法参数和集合或数组等位置,派生类的对象可以作为基类的对象处理。 发生此情况时,该对象的声明类型不再与运行时类型相同。
• 基类可以定义并实现虚方法,派生类可以重写这些方法,即派生类提供自己的定义和实现。 在运行时,客户端代码调用该方法,CLR 查找对象的运行时类型,并调用虚方法的重写方法。 因此,你可以在源代码中调用基类的方法,但执行该方法的派生类版本。
虚方法允许你以统一方式处理多组相关的对象。 例如,假定你有一个绘图应用程序,允许用户在绘图图面上创建各种形状。 你在编译时不知道用户将创建哪些特定类型的形状。 但应用程序必须跟踪创建的所有类型的形状,并且必须更新这些形状以响应用户鼠标操作。 你可以使用多态性通过两个基本步骤解决这一问题:
1. 创建一个类层次结构,其中每个特定形状类均派生自一个公共基类。
2. 使用虚方法通过对基类方法的单个调用来调用任何派生类上的相应方法。
首先,创建一个名为 Shape 的基类,并创建一些派生类,例如 Rectangle、Circle 和 Triangle。 为 Shape 类提供一个名为 Draw 的虚方法,并在每个派生类中重写该方法以绘制该类表示的特定形状。 创建一个 List 对象,并向该对象添加 Circle、Triangle 和 Rectangle。 若要更新绘图图面,请使用 foreach 循环对该列表进行循环访问,并对其中的每个 Shape 对象调用 Draw 方法。 虽然列表中的每个对象都具有声明类型 Shape,但调用的将是运行时类型(该方法在每个派生类中的重写版本)。
public class Shape { public int x { get; private set; } public int y { get; private set; } public int height { get; set; } public int weight { get; set; } public virtual void Draw() { Console.WriteLine("Base Draw Function"); } } public class Circle : Shape { public override void Draw() { Console.WriteLine("Draw a circle"); base.Draw(); } } public class Triangle : Shape { public override void Draw() { Console.WriteLine("Draw a Triangle"); base.Draw(); } } public class Rectangle : Shape { public override void Draw() { Console.WriteLine("Draw a Rectangle"); base.Draw(); } } class Program { static void Main(string[] args) { List<Shape> shape = new List<Shape>(3); shape.Add(new Circle()); shape.Add(new Triangle()); shape.Add(new Rectangle()); foreach (Shape s in shape) { s.Draw(); } Console.ReadKey(); } }
多态性概述 虚成员
当派生类从基类继承时,它会获得基类的所有方法、字段、属性和事件。 派生类的设计器可以选择是否
• 重写基类中的虚拟成员。
• 继承最接近的基类方法而不重写它
• 定义隐藏基类实现的成员的新非虚实现
仅当基类成员声明为 virtual 或 abstract 时,派生类才能重写基类成员。 派生成员必须使用 override 关键字显式指示该方法将参与虚调用
public class BaseClass { public virtual int Num { get { return 0; } } public virtual void Do() { Console.WriteLine("base func"); } } class DerivedClass:BaseClass { public override void Do() { Console.WriteLine("override func"); } public override int Num { get { return 0; } } } class Program { static void Main(string[] args) { BaseClass bc = new BaseClass(); bc.Do(); DerivedClass dc = new DerivedClass(); dc.Do(); BaseClass bcb = new DerivedClass(); bcb.Do(); Console.ReadKey(); } }
使用新成员隐藏基类成员
如果希望派生成员具有与基类中的成员相同的名称,但又不希望派生成员参与虚调用,则可以使用 new 关键字。new 关键字放置在要替换的类成员的返回类型之前。
public class BaseClass { public int Num { get { return 0; } } public void Do() { Console.WriteLine("base func"); } } class DerivedClass:BaseClass { public new void Do() { Console.WriteLine("override func"); } public new int Num { get { return 0; } } } class Program { static void Main(string[] args) { BaseClass bc = new BaseClass(); bc.Do(); DerivedClass dc = new DerivedClass(); dc.Do(); BaseClass bcb = new DerivedClass(); bcb.Do(); Console.ReadKey(); } }
阻止派生类重写虚函数
无论在虚拟成员和最初声明虚拟成员的类之间已声明了多少个类,虚拟成员永远都是虚拟的。 如果类 A 声明了一个虚拟成员,类 B 从 A 派生,类 C 从类 B 派生,则类 C 继承该虚拟成员,并且可以选择重写它,而不管类 B 是否为该成员声明了重写。派生类可以通过将重写声明为 sealed 来停止虚拟继承。 这需要在类成员声明中的 override 关键字前面放置 sealed关键字。通过使用 new 关键字,密封的方法可以由派生类替换。已替换或重写某个方法或属性的派生类仍然可以使用基关键字访问基类的该方法或属性(base.function)。
相关文章推荐
- Lua编程示例(二):面向对象、metatable对表进行扩展
- C#与.net高级编程 C#的多态介绍
- C#中面向对象编程机制之多态学习笔记
- 浅谈Lua的面向对象特性
- Lua面向对象之类和继承浅析
- JavaScript面向对象的两种书写方法以及差别
- 浅谈c# 面向对象之类与对象
- C#中的多态深入理解
- C#面向对象特征的具体实现及作用详解
- C# 面向对象的基本原则
- C#中多态、重载、重写区别分析
- 设计引导--一个鸭子游戏引发的设计理念(多态,继承,抽象,接口,策略者模式)
- 浅谈对c# 面向对象的理解
- Ruby面向对象编程详解
- php学习 面向对象 课件第1/2页
- PHP程序61条面向对象分析设计的经验小结
- 收集学习asp.net比较完整的面向对象开发流程
- javascript 面向对象编程 万物皆对象
- 不错的JavaScript面向对象的简单入门介绍第1/2页
- Python3 面向对象概述