`
zhangziyangup
  • 浏览: 1187243 次
文章分类
社区版块
存档分类
最新评论

C#中的多态现象和多态的多种实现

 
阅读更多

面向对象的特征封装、继承和多态。Polymorphism(多态性)来源于希腊单词,指“多种形态”。多态性的一个重要特征是方法的调用是在运行时确定而不是编译时。在.NET中用于实现多态性的关键词有virtual、override、abstract、interface。

一:virtual实现多态

shape类是通用的基类,draw是一个虚方法,每个派生类都可以有自己的override版本,在运行时可以用shape类的变量动态的调用draw方法。

publicclassShape

{

publicvirtualvoid Draw()

{

Console.WriteLine("base class drawing");

}

}

publicclassRectangle :Shape

{

publicoverridevoid Draw()

{

Console.WriteLine("Drawing a Rectangle");

}

}

publicclassSquare :Rectangle

{

publicoverridevoid Draw()

{

Console.WriteLine("Drawing a Square");

base.Draw();

}

}

classProgram

{

staticvoid Main(string[]args)

{

System.Collections.Generic.List<Shape>shapes =newList<Shape>();

shapes.Add(newRectangle());

shapes.Add(newSquare());

foreach(Shape s in shapes)

{

s.Draw();

}

Console.ReadKey();

/*运行结果

Drawing a Rectangle

Drawing a Square

Drawing a Rectangle

*/

}

}

方法、属性、事件、索引器都可以被virtual修饰,但是字段不可以。派生类必须用override表示类成员参与虚调用。假如把Square中的draw方法替换为用new 修饰,则表示draw方法不参与虚调用,而且是一个新的方法,只是名字和基类方法重名。

publicnewvoid Draw()

{

Console.WriteLine("Drawing a Square");

base.Draw();

}

这个方法在Main方法中的foreach中将不会被调用,它不是虚方法了。用new修饰符后的程序运行结果,

/*运行结果

Drawing a Rectangle

Drawing a Rectangle

*/

假如说虚方法在rectangle扩展后,不希望square扩展了,可以在方法前加上sealed修饰符,

如下

publicclassRectangle :Shape

{

publicsealedoverride voidDraw()

{

Console.WriteLine("Drawing a Rectangle");

}

}

当派生类重写某个虚拟成员时,即使该派生类的实例被当作基类的实例访问或者把派生类实例赋给父类变量进行访问,但是还是会调用派生类重写后的成员,可以把代码改为如下形式,

staticvoid Main(string[] args)

{

System.Collections.Generic.List<Shape>shapes =newList<Shape>();

shapes.Add((Shape)newRectangle());

shapes.Add((Shape)newSquare());

foreach(Shape s inshapes)

{

s.Draw();

}

Console.ReadKey();

/*运行结果

Drawing a Rectangle

Drawing a Square

Drawing a Rectangle

*/

}

二:abstract实现多态

被abstract修饰的方法,默认是虚拟的,但是不能出现virtual关键词修饰。被abstract修饰的类可以有已实现的成员,可以有自己的字段,可以有非abstract 修饰的方法,但是不能实例化因为抽象的东西是没有实例对应的。比如,有人让我们画个图形(抽象)是画不出来的,但是让画个矩形(具体)是可以画出来的。下面是用abstract实现的多态版本,

publicabstractclassShape

{

publicabstractvoid Draw();

}

publicclassRectangle :Shape

{

publicoverridevoid Draw()

{

Console.WriteLine("Drawing a Rectangle");

}

}

publicclassSquare :Rectangle

{

publicoverridevoid Draw()

{

Console.WriteLine("Drawing a Square");

base.Draw();

}

}

classProgram

{

staticvoid Main(string[]args)

{

System.Collections.Generic.List<Shape>shapes =newList<Shape>();

shapes.Add(newRectangle());

shapes.Add(newSquare());

foreach(Shape s in shapes)

{

s.Draw();

}

Console.ReadKey(); }

}

被abstract修饰的方法,在派生类中同样用override关键词进行扩展。同样可以用关键词sealed阻止派生类进行扩展。

interface实现多态

接口可由方法、属性、事件、索引器或这四种成员类型的任何组合构成。接口不能包含字段。接口成员默认是公共的,抽象的,虚拟的。若要实现接口成员,类中的对应成员必须是公共的、非静态的,并且与接口成员具有相同的名称和签名。下面是interface实现的多态版本

publicinterfaceIShape

{

voidDraw();

}

publicclassRectangle :IShape

{

publicvoid Draw()

{

Console.WriteLine("Drawing a Rectangle");

}

}

publicclassSquare:IShape

{

publicvoid Draw()

{

Console.WriteLine("Drawing a Square");

}

}

classProgram

{

staticvoid Main(string[]args)

{

System.Collections.Generic.List<IShape>shapes =newList<IShape>();

shapes.Add(newRectangle());

shapes.Add(newSquare());

foreach(IShape s inshapes)

{

s.Draw();

}

Console.ReadLine();

}

}

抽象类与接口

类可以实现无限个接口,但仅能从一个抽象(或任何其他类型)类继承。从抽象类派生的类仍可实现接口。msdn的在接口和抽象类的选择方面给的一些建议,

如果预计要创建组件的多个版本,则创建抽象类。抽象类提供简单易行的方法来控制组件版本。通过更新基类,所有继承类都随更改自动更新。另一方面,接口一旦创建就不能更改。如果需要接口的新版本,必须创建一个全新的接口。

如果创建的功能将在大范围的全异对象间使用,则使用接口。抽象类应主要用于关系密切的对象,而接口最适合为不相关的类提供通用功能。

如果要设计小而简练的功能块,则使用接口。如果要设计大的功能单元,则使用抽象类。

如果要在组件的所有实现间提供通用的已实现功能,则使用抽象类。抽象类允许部分实现类,而接口不包含任何成员的实现。

一个综合性的实例

publicinterfaceIShape

{

voidDraw();

}

publicclassShape:IShape

{

voidIShape.Draw()

{

Console.WriteLine("Shape IShape.Draw()");

}

publicvirtualvoid Draw()

{

Console.WriteLine("Shape virtual Draw()");

}

}

publicclassRectangle :Shape,IShape

{

voidIShape.Draw()

{

Console.WriteLine("Rectangle IShape.Draw()");

}

publicnewvirtualvoid Draw()

{

Console.WriteLine("Rectangle virtual Draw()");

}

}

publicclassSquare :Rectangle

{

publicoverridevoid Draw()

{

Console.WriteLine("Square override Draw()");

}

}

classProgram

{

staticvoid Main(string[]args)

{

Squaresqure = new Square();

Rectanglerect = squre;

Shapeshape = squre;

IShapeishape = squre;

squre.Draw();

rect.Draw();

shape.Draw();

ishape.Draw();

Console.ReadLine();

}

}

/*运行结果:

Square override Draw()

Square override Draw()

Shape virtual Draw()

Rectangle IShape.Draw()

*/

在这个程序里,把派生类实例赋给父类变量或者接口。对结果①无需解释。结果②,因为Draw方法是虚方法,虚方法的调用规则是调用离实例变量最近的override版本方法,Square类中的Draw方法是离实例square最近的方法,即使是把Square类型的实例赋值给Rectangle类型的变量去访问,仍然调用的是Square类重写的方法。对于结果③,也是虚方法调用,在子类Rectangle中的draw方法用new修饰,这就表明shape类中的virtual到此中断,后面Square中的override版是针对Rectangle中的Draw方法,此时,离square实例最近的实现就是Shape类中的Draw 方法,因为Shape类中的Draw方法没有override的版本只能调用本身的virtual版了。结果④,因为Rectangle重新声明实现接口IShape,接口调用同样符合虚方法调用规则,调用离它最近的实现,Rectangle中的实现比Shape中的实现离实例square更近。Rectangle中的IShape.Draw()方法是显式接口方法实现,对于它不能有任何的访问修饰符,只能通过接口变量访问它,同时也不能用virtual或者override进行修饰,也不能被派生类型调用。只能用IShape变量进行访问。如果类型中有显式接口的实现,而且用的是接口变量,默认调用显式接口的实现方法。

override和方法选择

publicclassBase

{

publicvirtualvoid Write(int num)

{

Console.WriteLine("int:" + num.ToString());

}

}

publicclassDerived :Base

{

publicoverridevoid Write(int num)

{

Console.WriteLine("derived:" + num.ToString());

}

publicvoid Write(doublenum)

{

Console.WriteLine("derived double:" + num.ToString());

}

分享到:
评论

相关推荐

    c#中应用多态的计算器

    在C#编程语言中,多态(Polymorphism)是面向对象编程的三大特性之一,另外两个是封装和继承。多态允许我们使用一个接口来处理不同类型的对象,从而简化代码,提高代码的可扩展性和复用性。在这个“C#中应用多态的...

    C#中多态现象和多态的实现方法

    本文实例讲述了C#中多态现象和多态的实现方法。分享给大家供大家参考。具体分析如下: 面向对象的特征封装、继承和多态。Polymorphism(多态性)来源于希腊单词,指“多种形态”。多态性的一个重要特征是方法的调用...

    C#继承和多态的应用

    C#继承和多态的应用

    关于C#继承多态的应用项目

    在C#编程语言中,继承和多态是面向对象编程的两大核心概念,它们极大地增强了代码的可重用性、灵活性和扩展性。本项目旨在通过实际操作来深入理解和应用这两个概念。 首先,让我们理解“继承”。继承允许一个类...

    C#继承,接口,多态的实现与区别

    在C#编程语言中,继承、接口和多态是面向对象编程的重要概念,它们共同构建了C#类体系的灵活性和可扩展性。下面将详细阐述这三个概念的实现方式、功能以及它们之间的区别。 首先,**继承(Inheritance)**是C#中类...

    一个经典c#多态的范例

    这段代码会根据实际的对象类型,分别调用`Dog`和`Cat`类中重写过的`Talk()`方法,实现了“统一调用,多种实现”的效果。这就是C#中多态的魅力所在,我们不需要知道数组中具体是什么类型的动物,只需通过基类的引用...

    c#多态 完全 通 源码

    在这个"完全通源码"的压缩包中,我们可以期待看到关于C#多态的实例和源代码,帮助我们深入理解和运用这个概念。 1. **多态的定义**:多态意味着“多种形态”。在C#中,多态主要体现在方法的重载(Overloading)和...

    C#第六章 初始继承和多态.pdf

    C#第六章 初始继承和多态.pdfC#第六章 初始继承和多态.pdfC#第六章 初始继承和多态.pdf C#第六章 初始继承和多态.pdfC#第六章 初始继承和多态.pdf

    C# 多态概念

    在C#语言中,多态是通过多种方式实现的,包括继承、接口实现以及虚方法与抽象方法等。本文将详细介绍C#中的多态概念,并探讨其实现机制及其应用场景。 #### 多态的基本定义 多态是指程序中能够处理多种数据类型的...

    C#试卷多态封装继承

    很好学基础E:\深入.NET\S2-C#内部测试.tif

    C#多态测试C#多态测试C#多态测试

    在这个“C#多态测试”主题中,我们将深入探讨C#中的多态性,包括方法的重载、重写、抽象类和接口,以及虚方法和非虚方法的区别。 一、方法的重载(Overloading) 在C#中,方法的重载是指在同一个作用域内,可以有多...

    C#多态技术及简单例子描述

    在C#中,多态性(Polymorphism)是面向对象编程的核心概念之一,它允许一个接口或基类引用调用不同的实现,从而提供更大的灵活性和代码重用。多态性分为编译时多态性和运行时多态性。 1. 编译时多态性: 编译时多态...

    VS2010 C# 多态实例

    在这个“VS2010 C# 多态实例”中,我们将深入探讨C#语言如何实现多态,以及如何在Visual Studio 2010环境下利用这一特性进行开发。 C#中的多态性主要体现在两个方面:方法的重载(Overloading)和方法的重写...

    C#封装继承多态

    这是关于C#封装继承多态的一个简单的例子,对于深入学习C#中封装继承多态将很有帮助!

    深入剖析C#的多态××××××

    在C#中,多态性分为两种类型:编译时的多态性和运行时的多态性。编译时的多态性主要通过方法重载实现,即在同一作用域内,用相同的名称但参数列表不同的方法。编译器根据传入的参数类型和数量自动选择正确的方法执行...

    C#课堂案例(多态)

    这在多态中扮演着关键角色,使得子类对象可以调用自己的版本,而不是父类的版本。 例如,上面的`Shape`类中的`GetArea`方法是虚方法,子类可以重写它以提供特定形状的面积计算。当我们有一个`Shape`类型的引用指向`...

    c#多态,接口等概念和方法

    **多态性**(Polymorphism)是面向对象编程的一个关键特性,它允许我们使用一个接口来表示多种类型,从而实现代码的通用性和灵活性。C#中的多态性主要体现在两个方面:方法的重载(Overloading)和方法的重写...

    C#面向对象编程-多态习题[整理].pdf

    C#面向对象编程-多态习题[整理].pdf

    C#中的继承和多态构建一个定义明确的类类型

    研究了oop的第一个支柱封装,探讨了如何使用继承来构建一族相关类

Global site tag (gtag.js) - Google Analytics