什么是多态
原文地址:http://blog.csdn.net/softart/archive/2007/10/27/1846041.aspx一.什么是多态(Polymorphism )多态(Polymorphism)是面向对象(Object-Oriented,OO)思想"三大特征"之一,其余两个分别是封装(Encapsulation)和继承(Inheritance)--可见多态的重要性。或者说,不懂得什么是多态就不能说懂得面向对象。 多态是一种机制、一种能力,而非某个关键字。它在类的继承中得以实现,在类的方法调用中得以体现。 先让我们看看MSDN里给出的定义: Through inheritance,a class can be used as more than one type; it can be used as its own type,any base types,or any interface type if it implements interfaces. This is called polymorphism. In C#,every type is polymorphic. Types can be used as their own type or as a Object instance,because any type automatically treats Object as a base type. 译文:通过继承,一个类可以被当作不止一个数据类型(type)使用,它可以被用做自身代表的数据类型(这是最常用的),还可以被当作它的任意基类 所代表的数据类型,乃至任意接口类型--前提是这个类实现了这个接口。这一机制称为"多态"。在C#中,所有的数据类型都是多态的。任意一个数据类型都可 以被当作自身来使用,也可以当作Object类型来使用(我怀疑原文有问题,那个instance可能是原作者的笔误),因为任何数据类型都自动以 Object为自己的基类。 呵呵,除非你已经早就知道了什么是多态然后翻过头来看上面一段话,不然我敢打保票--我是清清楚楚的,你是稀里糊涂的。OK,不难为大家了,我用几个句子说明一下多态的思想。 我们先把前文中提到的"接口"理解为"一组功能的集合",把"类"理解为功能的实现体。这样的例子多了去了。我们就拿生物界做比喻了: 功能集合1:呼吸系统 功能集合2:血液循环系统 功能集合3:神经系统 功能集合4:语言系统 类1:灵长类动物。此类实现了1到3功能集合。 类2:猴子类。继承自类1。新添加了"爬树"的功能。 类3:人类。继承自类1。同时实现了功能集合4。 类4:男人类。继承自类3。新添加了"写程序"的功能。 类5:女人类。继承自类3。新添加了"发脾气"的功能。 作业: 请大家把上面的关系用图画出来 OK,让我们看下面的话,判断对错: 1. 男人是男人 (√) 原因:本来就是! 2. 男人是人 (√) 原因:人类是男人类的基类 3. 男人是灵长类动物 (√)原因:灵长类是男人类的更抽象层基类 4. 男人是会说话的 (√) 原因:男人类的基类实现了语言系统 5. 女人是猴子 (×) 原因:如果我这么说,会被蹁死 6. 猴子是女人 (×) 原因:女人不是猴子的基类 7. 人会写程序 (×)原因:写程序方法是在男人类中才具体实现的 8. 女人会发脾气 (√) 原因:因为我说5.. 哈哈!现在你明白什么是多态了吧!其实是非常简单的逻辑思维。上面仅仅是多态的一个概念,下面我们通过代码去研习一下程序中的多态到底是什么。 二.多态的基础--虚函数(virtual )和重写(override )很多公司在面试的时候常拿下面几个问题当开胃小菜: 1. 如何使用virtual和override? 2. 如何使用abstract和override? 3. "重写"与"重载"一样吗? 4. "重写"、"覆盖"、"隐藏"是同一个概念吗? 顺便说一句:如果你确定能把上面的概念很熟练的掌握,发个Mail给我(bladey@tom.com ),也许你能收到一份薪水和福利都不错的Offer :p 今天我们学习多态,其实就是解决问题1。前面已经提到过,多态机制是依靠继承机制实现的。那么,在常规继承机制的基础之上,在基类中使用virtual函数,并在其派生类中对virtual函数进行override,那么多态机制就自然而然地产生了。 小议 virtual : 呵呵,我这人比较笨--有我的老师和同学为证--学东西奇慢无比,所以当初在C++中学习virtual的历程是我心中永远挥之不去的阴影..倒霉 就倒霉在这个"虚"字上了。"实"的我还云里雾里呢,更何况这"虚"的,"虚"的还没搞清楚呢,"纯虚"又蹦出来了, 我#@$%!^#&&!.. 还好,我挺过来了..回顾这段学习历程,我发现万恶之源就是这个"虚"字。 在汉语中,"虚"就是"无","无"就是"没有",没有的事情就"不可说"、"不可讲"--那还讲个X??老师也头疼,学生更头疼。拜初中语文老师所赐,我的语言逻辑还算过关,总感觉virtual function译为"虚函数"有点词不达意。 找来词典一查,virtual有这样一个词条: Existing or resulting in essence or effect though not in actual fact,form,or name: 实质上的,实际上的:虽然没有实际的事实、形式或名义,但在实际上或效果上存在或产生的: 例句: the virtual extinction of the buffalo. 野牛实际上已经绝迹(隐含的意思是"尽管野牛还木有死光光,但从效果上来讲..") 啊哦~~让我想起一句话: 有的人活着他已经死了; 有的人死了他还活着.. 不禁有点惊叹于母语的博大精深-- virtual function中的virtual应该译做"名存实亡 "而不是"虚"! OK,下面就让我们看看类中的virtual函数是怎么个"名存实亡"法。 例子 1 : 非 virtual / override 程序
代码分析: 1. 一上来,演员类、乐手类、吉他手类形成一个继承链。 2. 乐手类和吉他手类作为子类,都把其父类的DoShow()方法"隐藏"了。 3. 特别强调:"隐藏"不是"覆盖",后面要讲的"重写"才是真正的"覆盖"。 4. 隐藏是使用new修饰符实现的,但这个修饰符可以省略。 5. 隐藏(Hide)的含意是:父类的这个函数实际上还在,只是被子类的同名"藏起来"了。 6. 重写(override)与覆盖是同一个含意,只是覆盖并非编程的术语,但"覆盖"比较形象。 7. 主程序代码的上半部分是常规使用方法,没什么好说的。 8. 主程序代码的下半部分已经算是多态了,但由于没有使用virtual和override,多态最有价值的效果--个性化方法实现--没有体现出来。后面的例子专门体现这一点。 例子 2 : 应用 virtual / override ,真正的多态
// 调用的是引用类型所引用的实例的方法 // 引用类型本身的函数是virtual的 // 看似"存在",实际已经被其子类重写(不是隐藏,而是被kill掉了) // 这正是virtual所要表达的"名存实亡"的本意,而非一个"虚"字所能传达 代码分析: 1. 除了将继承链中最顶层基类的DoShow()方法改为用virtual修饰;把继承链中派生类的DoShow()方法改为override修饰以重写基类的方法。 2. 主程序代码没变,但下半部分产生的效果完全不同!请体会"引用变量本身方法"与"引用变量所引用实例的方法"的不同--这是关键。 多态成因的分析: 为什么会产生这样的效果呢?这里要提到一个"virtual表"的问题。我们看看程序中继承链的构成:Actor à Bandsman à Guitarist。因为派生类不但继承了基类的代码(确切地说是public代码)而且还有自己的特有代码(无论是不是与基类同名,都是自己特有的)。 从程序的逻辑视角来看,你可以这样想象:在内存中,子类的实例所占的内存块是在父类所占的内存块的基础上"追加"了一小块--拜托大家自己画画图。这多出 来的一小块里,装的就是子类特有的数据和代码。 我们仔细分析这几句代码: 1. Actor actor = new Actor(); //常规的声明及分配内存方法 2. Actor myActor1 = new Bandsman(); //正确:乐手是演员 3. Actor myActor2 = new Guitarist(); //正确:吉他手是演员 4. Guitarist myActor2 = new Actor(); //错误:想一想为什么? 乱弹: 多态,台湾的兄弟们喜欢称"多型",一样的。"多"表示在实例化引用变量的时候,根据用户当时的使用情况(这时候程序已经Release了,不能再修改了,程序员已经不能控制程序了)智能地给出个性化的响应。 多,谓之变。莫非"多态"亦可称为"变态"耶?咦.."变型"..让我想起Transformer来了。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |