C# 多态的实现

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

例1:

代码 
  1. public class Animal
  2. {
  3. public virtual void Eat()
  4. {
  5. Console.WriteLine("Animal eat");
  6. }
  7. }
  8.  
  9. public class Cat : Animal
  10. {
  11. public override void Eat()
  12. {
  13. Console.WriteLine("Cat eat");
  14. }
  15. }
  16.  
  17. public class Dog : Animal
  18. {
  19. public override void Eat()
  20. {
  21. Console.WriteLine("Dog eat");
  22. }
  23. }
  24.  
  25. class Tester
  26. {
  27. static void Main(string[] args)
  28. {
  29. Animal[] animals = new Animal[3];
  30.  
  31. animals[0] = new Animal();
  32. animals[1] = new Cat();
  33. animals[2] = new Dog();
  34.  
  35. for (int i = 0; i < 3; i++)
  36. {
  37. animals[i].Eat();
  38. }
  39. }
  40. }

输出如下:

Animal eat...

Cat eat...

Dog eat...

在上面的例子中,通过继承,使得Animal对象数组中的不同的对象,在调用Eat()方法时,表现出了不同的行为。

多态的实现看起来很简单,要完全理解及灵活的运用c#的多态机制,也不是一件容易的事,有很多需要注意的地方。

1. new的用法

先看下面的例子。

例2

代码 
  1. public class Animal
  2. {
  3. public virtual void Eat()
  4. {
  5. Console.WriteLine("Animal eat");
  6. }
  7. }
  8.  
  9. public class Cat : Animal
  10. {
  11. public new void Eat()
  12. {
  13. Console.WriteLine("Cat eat");
  14. }
  15. }
  16.  
  17. class Tester
  18. {
  19. static void Main(string[] args)
  20. {
  21. Animal a = new Animal();
  22. a.Eat();
  23.  
  24. Animal ac = new Cat();
  25. ac.Eat();
  26.  
  27. Cat c = new Cat();
  28. c.Eat();
  29. }
  30. }

运行结果为:

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:

代码 
  1. public class Animal
  2. {
  3. public virtual void Eat()
  4. {
  5. Console.WriteLine("Animal eat");
  6. }
  7. }
  8.  
  9. public class Dog : Animal
  10. {
  11. public override void Eat()
  12. {
  13. Console.WriteLine("Dog eat");
  14. }
  15. }
  16.  
  17. public class WolfDog : Dog
  18. {
  19. public override void Eat()
  20. {
  21. Console.WriteLine("WolfDog eat");
  22. }
  23. }
  24.  
  25. class Tester
  26. {
  27. static void Main(string[] args)
  28. {
  29. Animal[] animals = new Animal[3];
  30.  
  31. animals[0] = new Animal();
  32. animals[1] = new Dog();
  33. animals[2] = new WolfDog();
  34.  
  35. for (int i = 0; i < 3; i++)
  36. {
  37. animals[i].Eat();
  38. }
  39. }
  40. }

运行结果为:

Animal eat...

Dog eat...

WolfDog eat...

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

3. abstract-override实现多态

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

例4:

代码

  1. public abstract class Animal
  2. {
  3.     public abstract void Eat();
  4. }
  5.  
  6. public class Cat : Animal
  7. {
  8. public override void Eat()
  9. {
  10. Console.WriteLine("Cat eat");
  11. }
  12. }
  13.  
  14. public class Dog : Animal
  15. {
  16. public override void Eat()
  17. {
  18. Console.WriteLine("Dog eat");
  19. }
  20. }
  21.  
  22. public class WolfDog : Dog
  23. {
  24. public override void Eat()
  25. {
  26. Console.WriteLine("Wolfdog eat");
  27. }
  28. }
  29.  
  30. class Tester
  31. {
  32. static void Main(string[] args)
  33. {
  34. Animal[] animals = new Animal[3];
  35.  
  36. animals[0] = new Cat();
  37. animals[1] = new Dog();
  38. animals[2] = new WolfDog();
  39.  
  40. for (int i = 0; i < animals.Length; i++)
  41. {
  42. animals[i].Eat();
  43. }
  44. }
  45. }

运行结果为:

Cat eat...

Dog eat...

Wolfdog eat...

从上面可以看出,通过使用abstract-override可以和virtual-override一样地实现多态,包括多层继承也是一样的。不同之处在于,包含虚拟方法的类可以被实例化,而包含抽象方法的类不能被实例化。

转自https://www.cnblogs.com/ldyblogs/p/override.html

7.C# 多态的实现的更多相关文章

  1. Java中的多态

    1.多态:具有表现多种形态的能力的特征 父类: public abstract class Animal {public abstract void Say();} 子类: public class ...

  2. C# 工厂模式+虚方法(接口、抽象方法)实现多态

    面向对象语言的三大特征之一就是多态,听起来多态比较抽象,简而言之就是同一行为针对不同对象得到不同的结果,同一对象,在不同的环境下得到不同的状态. 实例说明: 业务需求:实现一个打开文件的控制台程序的d ...

  3. C#非常重要基础之多态

    前几天看了一位同志的博客,写的是关于他自己去支付宝面试的经历.过程大体是这样的:问答的时候,前面部分,作者都应答如流,说起自己经验如何之丰富,最后面试官问了作者一个问题:请简述多态的概念和作用.结果这 ...

  4. C++多态详解

    多态是面向对象的程序设计的关键技术.多态:调用同一个函数名,可以根据需要但实现不同的功能.多态体现在两个方面,我们以前学过的编译时的多态性(函数重载)和现在我们这一章将要学习的运行时的多态性(虚函数) ...

  5. 【那些年关于java多态应用】

    1.多态:具有表现多种形态的能力的特征 父类: public abstract class Animal { public abstract void Say();} 子类: public class ...

  6. JAVA多态

    多态是指当系统A访问系统B的服务时,系统B可以通过多种方式来提供服务,而这一切对系统A是透明的.比如动物园的饲养员能够给各种各样的动物喂食.下图显示了饲养员Feeder,食物Food和动物Animal ...

  7. C#多态“说来也说”——逻辑层BLL中的多态使用

    本文版权归博客园和作者吴双本人共同所有.欢迎转载,转载和爬虫请注明原文地址 http://www.cnblogs.com/tdws/p/5861842.html 昨天晚上,有个朋友说学了好久,依然没搞 ...

  8. java多态的理解

    面向对象语言中的类有三个特征,封装.继承.多态.封装与继承很好理解,那什么是多态呢? 1.什么是多态? 多态的定义:指允许不同类的对象对同一消息做出响应.即同一消息可以根据发送对象的不同而采用多种不同 ...

  9. java中如何实现多态

    复习基础知识 多态,就是重载和重写.重载发生在一个类中.重写发生在子类,意思就是子类重写父类相同名称的方法.刚学语言有的东西,不必搞得那么清楚,只有知道怎么用就行了,有的问题你要想真正把它搞得很懂,短 ...

  10. OC多态

    要点: 1.多种形态,引用的多种形态对于一个引用变量,可以指向任何类的对象.对于一个父类的引用(类与类之间有一种继承关系),可以指向子类,也可以指向本类,指向的类型不同.当通过此引用向对象发送消息,调 ...

随机推荐

  1. 计蒜客 31434 - 广场车神 - [DP+前缀和]

    题目链接:https://nanti.jisuanke.com/t/31434 小 D 是一位著名的车手,他热衷于在广场上飙车.每年儿童节过后,小 D 都会在广场上举行一场别样的车技大赛. 小 D 所 ...

  2. vue中的provide/inject的学习

    在 Vue.js 的 2.2.0+ 版本中添加加了 provide 和 inject 选项.用于父级组件向下传递数据.provide/inject:简单的来说就是在父组件(或者曾祖父组件)中通过pro ...

  3. 口语详解|为什么“how to say”是错的?

    你有没有说过一些印象深刻的中式英语呢?为什么有的英语会被称之为中式英语想必你大概知道,但是如何把中式英语使用正确你知道吗?今天,跟着小编来看看吧.By the way,今天的主角是"how ...

  4. beginner’s mistake

    PHP Advanced and Object-Oriented Programming 3rd Edition Related to modularity is abstraction: class ...

  5. https://pypi.org/project/py-mysql2pgsql/

    https://packages.ubuntu.com/trusty/postgresql-server-dev-9.3 所以使用下面的命令即可安装python-dev: yum install py ...

  6. 理解HTTP协议(转载)

    一.HTTP协议的演进 HTTP(HyperText Transfer Protocol)协议是基于TCP的应用层协议,它不关心数据传输的细节,主要是用来规定客户端和服务端的数据传输格式,最初是用来向 ...

  7. 在VMware运行Linux下,密码错误的原因

    抱歉,没有奏效,请再试一次 密码明明是正确的,但依旧报错 原因: 密码中有大写,但键盘中的大写按键在登录界面无效,需要按住shift才能实现大写.

  8. 安装IIS

    1.打开控制面板,找到“程序与功能”,点进去  2.选择打开或关闭Windows功能,选择internet信息服务,点击确定 3.安装完成后,再回到控制面板里面,找到“管理工具”,点进入 4.双击“I ...

  9. 洛谷P3295 萌萌哒 [SCOI2016] 倍增+并查集

    正解:倍增+并查集 解题报告: 传送门! 首先不难想到暴力?就考虑把区间相等转化成对应点对相等,然后直接对应点连边,最后求有几个连通块就好辣 然后看下复杂度,修改是O(n2)查询是O(n),就比较容易 ...

  10. 【python-opencv】图像直方图

    图像直方图使用到:python-opencv.matplotlib.numpy def plot_demo(image): print(len(image.ravel())) #统计image3通道的 ...