C#与.net高级编程 C#的多态介绍

用virtual关键字标记的方法称为虚方法,如果子类希望改变虚方法的实现细节就必须使用 override关键字。
抽象类
abstract关键字
防止创建毫无意义的基本类,使用abstract关键字创建抽象基类,防止被实例化
使用abstract关键字创建抽象方法,强制每一个子类重写特定的方法,abstract成员没有提供任何实现。
(注:抽象方法只可以定义在抽象类中,如果不是这样的话,就会收到编译器错误)
成员投影
如果派生类定义的成员和定义在蕨类中的成员一致,派生类投影了父类的版本。
如:我们从一个不是自己创建的类来创建子类就是很可能发生这样的情况(基类和子类出现同一个方法名。)
解决方案:
使用override关键字更新父版本,但是如果我们对定义基类的代码没有访问权限,我们就不能将方法修改为虚方法。
我们可以为派生类型的成员添加new 关键字。这样就可以表明派生类型的实现故意设计为隐藏父类的版本。

封装、继承、多态,面向对象的三大特性,前两项理解相对容易,但要理解多态,特别是深入的了解,对于初学者而言可能就会有一定困难了。我一直认为学习OO的最好方法就是结合实践,封装、继承在实际工作中的应用随处可见,但多态呢?也许未必,可能不经意间用到也不会把它跟“多态”这个词对应起来。在此抛砖引玉,大家讨论,个人能力有限,不足之处还请指正。

之前看到过类似的问题:如果面试时主考官要求你用一句话来描述多态,尽可能的精炼,你会怎么回答?当然答案有很多,每个人的理解和表达不尽相同,但我比较趋向这样描述:通过继承实现的不同对象调用相同的方法,表现出不同的行为,称之为多态。 


代码如下:

Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-->public class Animal
{
public virtual void Eat()
{
Console.WriteLine("Animal eat");
}
}

public class Cat : Animal
{
public override void Eat()
{
Console.WriteLine("Cat eat");
}
}

public class Dog : Animal
{
public override void Eat()
{
Console.WriteLine("Dog eat");
}
}

class Tester
{
static void Main(string[] args)
{
Animal[] animals = new Animal[3];

animals[0] = new Animal();
animals[1] = new Cat();
animals[2] = new Dog();

for (int i = 0; i < 3; i++)
{
animals[i].Eat();
}
}
}

输出如下:
Animal eat...
Cat eat...
Dog eat...

在上面的例子中,通过继承,使得Animal对象数组中的不同的对象,在调用Eat()方法时,表现出了不同的行为。
多态的实现看起来很简单,要完全理解及灵活的运用c#的多态机制,也不是一件容易的事,有很多需要注意的地方。

1.new的用法
先看下面的例子。
例2:


代码如下:

Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-->public class Animal
{
public virtual void Eat()
{
Console.WriteLine("Animal eat");
}
}

public class Cat : Animal
{
public new void Eat()
{
Console.WriteLine("Cat eat");
}
}

class Tester
{
static void Main(string[] args)
{
Animal a = new Animal();
a.Eat();

Animal ac = new Cat();
ac.Eat();

Cat c = new Cat();
c.Eat();
}
}

运行结果为:
Animal eat...
Animal eat...
Cat eat...

可以看出,当派生类Cat的Eat()方法使用new修饰时,Cat的对象转换为Animal对象后,调用的是Animal类中的Eat()方法。其实可以理解为,使用new关键字后,使得Cat中的Eat()方法和Animal中的Eat()方法成为毫不相关的两个方法,只是它们的名字碰巧相同而已。所以, Animal类中的Eat()方法不管用还是不用virtual修饰,也不管访问权限如何,或者是没有,都不会对Cat的Eat()方法产生什么影响(只是因为使用了new关键字,如果Cat类没用从Animal类继承Eat()方法,编译器会输出警告)。

我想这是设计者有意这么设计的,因为有时候我们就是要达到这种效果。严格的说,不能说通过使用new来实现多态,只能说在某些特定的时候碰巧实现了多态的效果。

2.override实现多态
真正的多态使用override来实现的。回过去看前面的例1,在基类Animal中将方法Eat()用virtual标记为虚拟方法,再在派生类Cat和Dog中用override对Eat()修饰,进行重写,很简单就实现了多态。需要注意的是,要对一个类中一个方法用override修饰,该类必须从父类中继承了一个对应的用virtual修饰的虚拟方法,否则编译器将报错。

好像讲得差不多了,还有一个问题,不知道你想没有。就是多层继承中又是怎样实现多态的。比如类A是基类,有一个虚拟方法method()(virtual修饰),类B继承自类A,并对method()进行重写(override修饰),现在类C又继承自类B,是不是可以继续对method()进行重写,并实现多态呢?看下面的例子。

例3:


代码如下:

Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-->public class Animal
{
public virtual void Eat()
{
Console.WriteLine("Animal eat");
}
}

public class Dog : Animal
{
public override void Eat()
{
Console.WriteLine("Dog eat");
}
}

public class WolfDog : Dog
{
public override void Eat()
{
Console.WriteLine("WolfDog eat");
}
}

class Tester
{
static void Main(string[] args)
{
Animal[] animals = new Animal[3];

animals[0] = new Animal();
animals[1] = new Dog();
animals[2] = new WolfDog();

for (int i = 0; i < 3; i++)
{
animals[i].Eat();
}
}
}

运行结果为:
Animal eat...
Dog eat...
WolfDog eat...

在上面的例子中类Dog继承自类Animal,对方法Eat()进行了重写,类WolfDog又继承自Dog,再一次对Eat()方法进行了重写,并很好地实现了多态。不管继承了多少层,都可以在子类中对父类中已经重写的方法继续进行重写,即如果父类方法用override修饰,如果子类继承了该方法,也可以用override修饰,多层继承中的多态就是这样实现的。要想终止这种重写,只需重写方法时用sealed关键字进行修饰即可。

3. abstract-override实现多态
先在我们在来讨论一下用abstract修饰的抽象方法。抽象方法只是对方法进行了定义,而没有实现,如果一个类包含了抽象方法,那么该类也必须用abstract声明为抽象类,一个抽象类是不能被实例化的。对于类中的抽象方法,可以再其派生类中用override进行重写,如果不重写,其派生类也要被声明为抽象类。看下面的例子。
例4:


代码如下:

Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/--> public abstract class Animal
{
    public abstract void Eat();
}

public class Cat : Animal
{
public override void Eat()
{
Console.WriteLine("Cat eat");
}
}

public class Dog : Animal
{
public override void Eat()
{
Console.WriteLine("Dog eat");
}
}

public class WolfDog : Dog
{
public override void Eat()
{
Console.WriteLine("Wolfdog eat");
}
}

class Tester
{
static void Main(string[] args)
{
Animal[] animals = new Animal[3];

animals[0] = new Cat();
animals[1] = new Dog();
animals[2] = new WolfDog();

for (int i = 0; i < animals.Length; i++)
{
animals[i].Eat();
}
}
}

运行结果为:
Cat eat...
Dog eat...
Wolfdog eat...
从上面可以看出,通过使用abstract-override可以和virtual-override一样地实现多态,包括多层继承也是一样的。不同之处在于,包含虚拟方法的类可以被实例化,而包含抽象方法的类不能被实例化。
以上就是我对c#中多态的一些浅薄的认识,如有错误的地方,欢迎批评指正!

(0)

相关推荐

  • C#中多态、重载、重写区别分析

    本文实例总结了C#中多态.重载与重写的概念与区别.对于初学C#的朋友来说有不错的参考价值.分享给大家供大家参考.具体分析如下: 重写:是指重写基类的方法,在基类中的方法必须有修饰符virtual,而在子类的方法中必须指明override. 格式如下: 1.在基类中: public virtual void myMethod() { } 2.在子类中: public override void myMethod() { } 重写以后,用基类对象和子类对象访问myMethod()方法,结果都是访问在

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

    本文实例讲述了C#中多态现象和多态的实现方法.分享给大家供大家参考.具体分析如下: 面向对象的特征封装.继承和多态.Polymorphism(多态性)来源于希腊单词,指"多种形态".多态性的一个重要特征是方法的调用是在运行时确定而不是编译时.在.NET中用于实现多态性的关键词有virtual.override.abstract.interface. 一.virtual实现多态   shape类是通用的基类,draw是一个虚方法,每个派生类都可以有自己的override版本,在运行时可以

  • C# 多态性的深入理解

    MSDN 上面的定义:通过继承,一个类可以有多种类型:可以用作它自己的类型,任何基类型,或者在实现接口时用作任何接口的类型.从两个方面来说明多态1.在运行时,方法参数和集合或者是数组等位置,派生类的对象都可以作为基类的对象处理,发生此情况时,该对象的声明类型不再与运行时类型相同.2.基类定义实现虚方法,派生类重写这些方法,在运行时,CLR会查找运行时类型,并且调用派生类重写的方法. 复制代码 代码如下: class Shape    {        public virtual void Dr

  • c#基础学习之多态

    最近在看一本书<你必须知道的.Net>,书涵盖的内容比较多,对于c#,.Net平台以往所学的零散东西有了慢慢的总结和新的认识.把一些基础的东西记录于此. 先说说多态吧: 1.基类继承式多态 如书中所说,基类继承式多态的关键是继承体系的设计与实现.书中举了个简单的列子 复制代码 代码如下: Files myFile=new WORDFile(); myFile.open(); myFile是一个父类Files变量,保持了指向子类WORDFile实例的引用,然后调用一个虚方法Open,具体的调用则

  • c#继承与多态使用示例

    继承和多态 派生类具有基类所有非私有数据和行为以及新类自己定义的所有其他数据或行为,即子类具有两个有效类型:子类的类型和它继承的基类的类型. 对象可以表示多个类型的能力称为多态性. 多态性示例 复制代码 代码如下: public class Parent    {        public Parent() { }        public void MethodA()        {            Console.WriteLine("调用MethodA()");   

  • C#中的多态深入理解

    封装.继承.多态,面向对象的三大特性,前两项理解相对容易,但要理解多态,特别是深入的了解,对于初学者而言可能就会有一定困难了.我一直认为学习OO的最好方法就是结合实践,封装.继承在实际工作中的应用随处可见,但多态呢?也许未必,可能不经意间用到也不会把它跟"多态"这个词对应起来.在此抛砖引玉,大家讨论,个人能力有限,不足之处还请指正. 之前看到过类似的问题:如果面试时主考官要求你用一句话来描述多态,尽可能的精炼,你会怎么回答?当然答案有很多,每个人的理解和表达不尽相同,但我比较趋向这样描

  • C#基础继承和多态详解

    继承 在现有类(称为基类.父类)上建立新类(称为派生类.子类)的处理过程为继承.派生类能自动获取基类(除了构造函数和析构函数外的所有成员),可以在派生类中添加新的属性和方法扩展其功能. 复制代码 代码如下: using System;using System.Collections.Generic;using System.Linq;using System.Web; public class Person{ private string _id;    public string id   

  • C#中面向对象编程机制之多态学习笔记

    C#的多态性: 我的理解是:同一个操作,作用于不同的对象时,会有不同的结果,即同一个方法根据需要,作用于不同的对象时,会有不同的实现. C#的多态包括:接口多态,继承多态. 其中继承多态又包括通过虚拟方法实现的多态和通过抽象方法实现的多态性 例如:基类动物都有吃的方法,但是不同的动物吃的东西就会不一样,例如狼吃肉,羊吃草,这样"吃"的这个方法就要在派生类里面重新实现以下,运行时,通过指向基类的指针,来调用实现派生类中的方法. 接下来举例实现多态性. 1. 接口多态性 把动物"

  • C#使用虚拟方法实现多态

    本文实例讲述了C#使用虚拟方法实现多态.分享给大家供大家参考.具体分析如下: 我们看一个例子,假若有一个动物类,类中用方法cry()描述动物的叫声,不同的动物的叫声是不一样的.根据继承的特征,把类中公共部分的内容放在父类中,那么cry()方法就应该放在父类中,根据这样的思路编写程序如下: using System; class Anmial { public void Cry() { Console.WriteLine("这是动物的叫声"); } } class Dog: Anmial

  • C#与.net高级编程 C#的多态介绍

    用virtual关键字标记的方法称为虚方法,如果子类希望改变虚方法的实现细节就必须使用 override关键字. 抽象类 abstract关键字 防止创建毫无意义的基本类,使用abstract关键字创建抽象基类,防止被实例化 使用abstract关键字创建抽象方法,强制每一个子类重写特定的方法,abstract成员没有提供任何实现. (注:抽象方法只可以定义在抽象类中,如果不是这样的话,就会收到编译器错误) 成员投影 如果派生类定义的成员和定义在蕨类中的成员一致,派生类投影了父类的版本. 如:我

  • 《JavaScript高级编程》学习笔记之object和array引用类型

    本文给大家分享我的javascript高级编程学习笔记之object和array引用类型,涉及到javascript引用类型相关知识,大家一起看看把. 1. Object类型 大多数引用类型值都是Object类型的实例:而且Object也是ECMAScript中使用最多的一个类型. 创建Object实例有如下两种方式: new操作符后跟Object构造函数: var person=new Object( ); person.name="webb"; person.age=25; 对象字

  • Mac OS X 10.8 中编译APUE(Unix环境高级编程)的源代码过程

    最近在温习APUE(<unix环境高级编程>),以前都是在linux下搞,现在打算在自己机器弄下,于是google了下,把编译的事情搞定了,修改了一些教程的一些错误,比如下载链接之类的. 1.下载源文件,我这里是第二版,貌似第三版的英文版出来了... 复制代码 代码如下: wget http://www.apuebook.com/src.2e.tar.gz 2.解压 复制代码 代码如下: tar zxf src.2e.tar.gz 3.修改些东西 复制代码 代码如下: cd apue.2e/

  • Python高级编程之继承问题详解(super与mro)

    本文实例讲述了Python高级编程之继承问题.分享给大家供大家参考,具体如下: 多继承问题 1.单独调用父类: 一个子类同时继承自多个父类,又称菱形继承.钻石继承. 使用父类名.init(self)方式调用父类时: 例: class Parent(object): def __init__(self, name): self.name = name print('parent的init结束被调用') class Son1(Parent): def __init__(self, name, age

  • Python高级编程之消息队列(Queue)与进程池(Pool)实例详解

    本文实例讲述了Python高级编程之消息队列(Queue)与进程池(Pool).分享给大家供大家参考,具体如下: Queue消息队列 1.创建 import multiprocessing queue = multiprocessing.Queue(队列长度) 2.方法 方法 描述 put 变量名.put(数据),放入数据(如队列已满,则程序进入阻塞状态,等待队列取出后再放入) put_nowait 变量名.put_nowati(数据),放入数据(如队列已满,则不等待队列信息取出后再放入,直接报

  • PHP高级编程之消息队列原理与实现方法详解

    本文实例讲述了PHP高级编程之消息队列原理与实现方法.分享给大家供大家参考,具体如下: 1. 什么是消息队列 消息队列(英语:Message queue)是一种进程间通信或同一进程的不同线程间的通信方式 2. 为什么使用消息队列 消息队列技术是分布式应用间交换信息的一种技术.消息队列可驻留在内存或磁盘上,队列存储消息直到它们被应用程序读出.通过消息队列,应用程序可独立地执行,它们不需要知道彼此的位置.或在继续执行前不需要等待接收程序接收此消息. 3. 什么场合使用消息队列 你首先需要弄清楚,消息

  • Node.js高级编程cluster环境及源码调试详解

    目录 前言 准备调试环境 编译 Node.js 准备 IDE 环境 Cluster 源码调试 SharedHandle RoundRobinHandle 为什么端口不冲突 SO_REUSEADDR 补充 SharedHandle 和 RoundRobinHandle 两种模式的对比 前言 日常工作中,对 Node.js 的使用都比较粗浅,趁未羊之际,来学点稍微高级的,那就先从 cluster 开始吧. 尼古拉斯张三说过,“带着问题去学习是一个比较好的方法”,所以我们也来试一试. 当初使用 clu

  • C++关于指针,继承和多态介绍

    目录 指针 指针和继承 指针.继承和多态 指针 我们在书本上学到的指针基本上都是:首先,指针是一个变量:其次,这个变量存储的值是一个地址.这个是对指针的一个基本理解,最近在编程中发现了一些新的东西. 首先,指针不仅仅是一个地址,还存在一个和所指向内容大小相关的值,如下代码: #include<iostream> using namespace std; int main() { int a = 10; int *pa = &a; cout << "pa: &quo

  • java面向对象继承与多态介绍

    目录 一.概述 二.继承 2.1 继承的概述 2.2 继承机制 2.3 类中属性,方法的继承与覆盖 2.4 super 关键字 三. 多态 总结 一.概述 面向对象程序设计的三大原则是封装性,继承性和多态性.继承性是子类自动共享父类的数据和方法的机制,它是由类的派生功能体现的.继承具有传递性,使得一个类可以继承另一个类的属性和方法,这样通过抽象出共同的属性和方法组件新的类,便于代码的重用.而多态是指不同类型的对象接收相同的消息时产生不同的行为,这里的消息主要是对类成员函数的调用,而不同的行为是指

  • Java并发编程之线程状态介绍

    目录 线程状态概述 睡眠sleep方法 等待和唤醒 等待唤醒的一个小例子 线程状态概述 线程由生到死的完整过程: 当线程被创建并启动以后,它既不是一启动就进入了执行状态,也不是一直处于执行状态.在线程的生命周期中,有几种状态呢?在API中java.lang.Thread.State这个枚举中给出了六种线程状态: 线程状态 导致状态发生条件 NEW(新建) 线程刚被创建,但是并未启动.还没调用start方法.MyThread t = new MyThread只有线程对象,没有线程特征. Runna

随机推荐