通过上篇文章 继承的本质 深入介绍了继承过程中对象的的创建过程,相信对继承已经有了一个深入的理解,本文则详细剖析一下面向对象设计的另一要素多态(Polymorphsim)。

什么是多态

官方MSDN上是这样描述的点此可查看原文连接:

Polymorphism is a Greek word that means "many-shaped" and it has two distinct aspects:

At run time, objects of a derived class may be treated as objects of a base class in places such as method parameters and collections or arrays. When this occurs, the object's declared type is no longer identical to its run-time type.

Base classes may define and implement virtual methods, and derived classes can override them, which means they provide their own definition and implementation. At run-time, when client code calls the method, the CLR looks up the run-time type of the object, and invokes that override of the virtual method. Thus in your source code you can call a method on a base class, and cause a derived class's version of the method to be executed.

大体意思就是:

  • 在运行时,对象的类型可以和运行时类型不同,派生类在某些地方可以被替换成基类,如方法的参数,集合或者数组。
  • 基类可以定义或实现虚方法,派生类能够重写父类的虚方法,这就意味派生类可以提供他们自己的定义和实现。在运行时,当客户端代码调用这些方法,CLR查找对象的运行时类型,并调用重写的虚方法。因此,你可以使用基类类型调用方法,从而执行派生类的一个实现。ps:翻译的水平一般,大体意思应该写出来了 :)

总结一下就是:

  • 1.派生类(子类)可以以基类(父类)类型出现;
  • 2.在运行时,派生类(子类)以自己的方式来实现;
  • 3.派生类(子类)以基类(父类)的类型使用时,只能使用父类共有或重写的方法,即特有的属性和方法不可以使用;

通俗简单来说就是,声明的时候是基类的类型,而实例化(new)的是派生类,举个栗子

public class Food
{
private string name = "Food"; public virtual string GetName()
{
return name;
}
} public class Bread : Food
{
private string name="Bread"; public override string GetName()
{
return name;
}
} public class ButterBread : Bread
{
private string name = "ButterBread"; public override string GetName()
{
return name;
}
}

Food food = new Bread(); 当我们调用 food.GetName() 时,执行的是 Bread.GetName() 方法,得到的是 "Bread"。如果我们这么写Food food = new ButterBread();,当调用 food.GetName() 时,执行的则是 ButterBread.GetName() 方法,这就是多态,有没有很简单!允许同一个类型具有不同的行为,通过例子是不是比上文扯的一堆要更好理解。

一张图轻松GET多态本质

相信上图很直观的对比了Food food = new Bread();和Bread bread = new Bread();之前的区别:二者唯一的不同是在堆栈上维护的Bread实例的地址引用类型不同,food是Food类型的,bread是Bread类型的,但是二者指向的GCHeap上的实例都是Bread类型的实例。简单说明下,TypeHandle(类型句柄)是指向加载该类型的相关元数据信息包括方发表,静态字段等。CLR再第一次加载类型的时候就会创建该类型的方法表,并按继承关系将所有父类的方法copy一份,重写的方法会使用自己的方法覆盖掉。所以多态实际上在运行时执行的还是具体实例化类型的方法表。分享下我一般这么理解:我们吃的是食物,而它是面包。说到底还是要看吃到的是啥。关于详细的LoaderHeap介绍可以参考文末参考链接。

一些思考

面对日渐复杂多变的业务需求,如何使我们的程序更灵活,易扩展,当然是面向抽象编程了,抽象即稳定的,而多态是我们得以实现这一原则的基础。同时掌握了继承多态之后,我们才能更好的学习和理解设计模式。另外发现:看英文的文章比看中文的更容易理解。大家尽量多看些英文的技术文章,不要怕!手边常备个词典就好。

参考

深入理解.net - 2.多态 Polymorphsim的更多相关文章

  1. 深入理解OOP(三):多态和继承(动态绑定和运行时多态)

    在前面的文章中,我们介绍了编译期多态.params关键字.实例化.base关键字等.本节我们来关注另外一种多态:运行时多态, 运行时多态也叫迟绑定. 深入理解OOP(一):多态和继承(初期绑定和编译时 ...

  2. 深入理解OOP(二):多态和继承(继承)

    本文是深入浅出OOP第二篇,主要说说继承的话题. 深入理解OOP(一):多态和继承(初期绑定和编译时多态) 深入理解OOP(二):多态和继承(继承) 深入理解OOP(三):多态和继承(动态绑定和运行时 ...

  3. Java基础之理解封装,继承,多态三大特性

    目录 封装 继承 多态 封装 封装隐藏了类的内部实现机制,可以在不影响使用的情况下改变类的内部结构,同时也保护了数据.对外界而已它的内部细节是隐藏的,暴露给外界的只是它的访问方法. 代码理解 publ ...

  4. 看懂下面C++代码才说你理解了C++多态虚函数!

    #include <iostream> using namespace std ; class Father { private :  virtual void Say()  //只有添加 ...

  5. 理解Go的多态实现

    总结两点: 在Go中,定义一个interface类型,该类型说明了它有哪些方法.使用时,在函数中,将该interface类型作为函数的形参,任意一个实现了interface类型的实参都能作为该inte ...

  6. 理解java的 多态

    http://www.cnblogs.com/chenssy/p/3372798.html

  7. 深入理解OOP(四): 多态和继承(抽象类)

    在本文中,我们讨论OOP中的热点之一:抽象类.抽象类在各个编程语言中概念是一致的,但是C#稍微有些不一样.本文中我们会通过代码来实现抽象类,并一一进行解析. 深入理解OOP(一):多态和继承(初期绑定 ...

  8. 深入理解OOP(第一天):多态和继承(初期绑定和编译时多态)

    在本系列中,我们以CodeProject上比较火的OOP系列博客为主,进行OOP深入浅出展现. 无论作为软件设计的高手.或者菜鸟,对于架构设计而言,均需要多次重构.取舍,以有利于整个软件项目的健康构建 ...

  9. python中对多态的理解

    目录 python中对多态的理解 一.多态 二.多态性 三.鸭子类型 python中对多态的理解 一.多态 多态是指一类事物有多种形态,比如动物类,可以有猫,狗,猪等等.(一个抽象类有多个子类,因而多 ...

随机推荐

  1. 移动前端的html5 head 头标签

    DOCTYPE DOCTYPE(Document Type),该声明位于文档中最前面的位置,处于 html 标签之前,此标签告知浏览器文档使用哪种 HTML 或者 XHTML 规范. 使用 HTML5 ...

  2. 工作流Activiti5.13学习笔记(一)

    了解工作流 1.工作流(Workflow),就是“业务过程的部分或整体在计算机应用环境下的自动化”,它主要解决的是“使在多个参与者之间按照某种预定义的规则传递文档.信息或任务的过程自动进行,从而实现某 ...

  3. C语言博客作业--嵌套循环

    一.PTA实验作业 题目1:7-4 换硬币 2 .设计思路 第一步:定义3个整型变量i,j,k用于循环,定义3个整型变量x,count,total分别用于储存零钱数额,换法个数,硬币数量: 第二步:输 ...

  4. Beta冲刺NO.6

    Beta冲刺 第六天 1. 昨天的困难 1.对于设计模式的应用不熟悉,所以在应用上出现了很大的困难. 2.SSH中数据库的管理是用HQL语句实现的,所以在多表查询时出现了很大的问题. 3.页面结构太凌 ...

  5. verilog学习笔记(0)

    assign赋值语句根本不允许出现在always语句块中 位于begin/end块内的多条阻塞赋值语句是串行执行的; 但是多条非阻塞赋值语句却是并行执行的,这些非阻塞赋值语句都会在其中任何一条语句执行 ...

  6. Flask 扩展 自定义扩展

    创建一个为视图访问加日志的扩展Flask-Logging,并从中了解到写Flask扩展的规范. 创建工程 先创建一个工程,目录结构如下: flask-logging/ ├ LICENSE # 授权说明 ...

  7. 小草手把手教你 LabVIEW 串口仪器控制——初识VISA串口

    有些人,学习一样东西时候,喜欢现成的例子.很多人学习一门技术,都喜欢现成的例子开始,比如学单片机的啊,最开始都是修改的例子吧,学语言的也是.最开始都是模仿.这个年头看书上的理论知识太浪费时间了.所以啊 ...

  8. Flask学习 一 基本结构

    -from flask import Flask +from flask import Flask,render_template -from flask import request -from f ...

  9. nyoj 鸡兔同笼

    鸡兔同笼 时间限制:3000 ms  |  内存限制:65535 KB 难度:1   描述 已知鸡和兔的总数量为n,总腿数为m.输入n和m,依次输出鸡和兔的数目,如果无解,则输出"No an ...

  10. 10-TypeScript中的接口

    接口是一种规约的约定,从接口继承的类必须实现接口的约定.在高级开发中,通常接口是用于实现各种设计模式的基础,没有接口,设计模式无从谈起. 定义接口: interface ILog{ recordlog ...