黑马程序员_多态性
来源:互联网 发布:配置网络 ubuntu 编辑:程序博客网 时间:2024/05/01 07:53
---------------------- <a href="http://edu.csdn.net"target="blank">ASP.Net+Android+IOS开发</a>、<a href="http://edu.csdn.net"target="blank">.Net培训</a>、期待与您交流! ----------------------
面向对象的第三个主要特性。
多态性是同一操作作用于不同的类的对象,由不同的类进行不同的解释,最终产生不同的执行效果。
多态性按照产生多态行为的时间分为:编译时多态与运行时多态。
1 编译时多态性
编译时多态是指通过设置不同的方法签名,在编译时由编译器根据方法的签名决定调用何种方法。
通过指定方法的访问级别(例如 public或 private)、可选修饰符(例如 abstract或 sealed)、返回值、名称和任何方法参数,可以在类或结构中声明方法。这些部分统称为方法的“签名”。
使用不同的方法签名实现多态性称为方法重载。为进行方法重载,方法的返回类型不是方法签名的一部分。但是,在确定委托和委托所指向方法之间的兼容性时,返回类型是方法签名的一部分。
安装具体签名的不同可以分为:参数类型或数量重载、输出与输入型参数引用重载。
1.1 参数类型或数量重载
在方法重载时,实参与形参一一对应,如果相应位置类型相同且方法参数数量相等,则完成匹配,即实现同名方法不同参数的重载。
如有下面方法:
void method() { Console.WriteLine("is a zero parameter"); } void method(int i) { Console.WriteLine("is a one parameter"); } void method(int i, double d) { Console.WriteLine("is a two parameter"); }
当调用函数
this.method(1, 2.0);
会调用第三个方法,输出:is a two parameter。
1.2 输出与输入型参数引用重载
输入引用从参数使用 ref关键字修饰,在方法调用传递过程中,不同于值传递,传递的是值在内存中的地址,由此,在方法内对参数的修改会作用至实参本身。
输出引用参数使用 out关键字修饰,类似于输入引用参数,但在调用方法前不需要对变量进行初始化。
由于本篇的重点是运行时多态,在对编译时多态介绍比较简单,仅作参考。
2 运行时多态性
运行时多态指在基本类中定义虚方法,在派生类中重新定义方法或覆盖虚方法,在发生对象调用时,由公共语言运行时(CLR)根据对象类型决定调用何种方法。
虚方法允许您以统一方式处理多组相关的对象。由虚方法引出的多态性有多重情形,以下着重介绍3种情形。
2.1 新成员隐藏基类成员
通过 new关键字,在派生类中重新定义一个与基类相同名字方法,在使用该派生类的实例被当作基类的实例访问,会调用基类成员方法。
如下示例:
public class BaseClass { public void DoWork() { Console.WriteLine("base Class do work"); } } public class DerivedClass : BaseClass { public new void DoWork() { Console.WriteLine("derived Class do work"); } }
执行以下语句时,
DerivedClass D = new DerivedClass(); D.DoWork(); BaseClass B = (BaseClass)D; B.DoWork();
会输出如下结果。
derivedClass do work
baseClass do work
程序表面,当派生类DerivedClass实例 D被当做基类BaseClass实例 B调用方法 DoWork()时,调用的是基类 baseClass的DoWork()方法。
2.2 虚成员
使用virtual在基类中定义虚成员方法,使用override在派生类中覆盖虚方法,从而使得在使用该派生类的实例被当作基类的实例访问,会调用派生类成员方法。
如下示例:
public class BaseClass { public virtual void DoWork() { Console.WriteLine("base Class do work"); } } public class DerivedClass : BaseClass { public override void DoWork() { Console.WriteLine("derived Class do work"); } }
执行以下语句时,
DerivedClass D = new DerivedClass(); D.DoWork(); BaseClass B = (BaseClass)D; B.DoWork();
会输出如下结果。
derivedClass do work
derivedClass do work
程序表面,当派生类中对基类方法进行覆盖,派生类的实例 D被当做基类实例 B调用方法时,仍然调用的是派生类DoWork()方法。
2.3 阻止派生类重写虚拟成员
使用关键字sealed阻止派生类重写虚方法,基类至sealed修饰的派生类将继续沿用成员继承机制,而对sealed修饰的派生类再派生时,将使用新成员隐藏基类成员机制。
示例如下:
public class A { public virtual void DoWork() { Console.WriteLine("a do work"); } } public class B : A { public override void DoWork() { Console.WriteLine("b do work"); } } public class C : B { public sealed override void DoWork() { Console.WriteLine("c do work"); } } public class D : C { public new void DoWork() { Console.WriteLine("d do work"); } }
执行以下语句时,
D d = new D(); Console.WriteLine("d"); d.DoWork(); C c = (C)d; Console.WriteLine("c"); c.DoWork(); B b = (B)d; Console.WriteLine("b"); b.DoWork(); A a = (A)d; Console.WriteLine("a"); a.DoWork();
会输出如下结果。
d
d do work
c
c do work
b
c do work
a
c do work
程序表明,派生类实例对象d被当做基类实例对象c调用DoWork()方法时,执行的是基类 c的方法;派生类实例对象d被当做基类实例对象b调用DoWork()方法时,执行的是基类 c的方法;派生类实例对象d被当做基类实例对象a调用DoWork()方法时,执行的是基类 c的方法,符合新成员隐藏基成员、虚方法机制。
在此不妨谈谈其具体实现机制,当派生类对象被强制类型转换赋值给基类对象时(这里有个著名的里氏法则,子类都可以向父类转化,反之不行,具体证明我也不会),基类对象是拿着派生类的引用,也就是说地址还指向派生类的对象,当使用override覆盖时,派生类对继承过来的基类成员会重新定义,也就是派生类中的基类副本会发生改变,但这并不会影响基类本身的定义,因而当派生类对象被当做基类对象访问时,是基类调用,但是是派生类内的基类发生调用,因而也就调用的是我们在派生类中定义的覆盖成员;而使用 new定义新的成员并不会改变派生类中基类的副本,因而当派生类对象被当做基类对象访问时,还是由派生类中的基类副本,调用其原本的基类中的成员;而密封不过是阻止了虚函数在派生类中被覆盖,并没有从根本上引入新的机制。由于认知有限,难免让各位见笑了,如有高见,可以留言。
参考
C# 编程指南
C# 自学手册
---------------------- <a href="http://edu.csdn.net"target="blank">ASP.Net+Android+IOS开发</a>、<a href="http://edu.csdn.net"target="blank">.Net培训</a>、期待与您交流! ----------------------
- 黑马程序员_多态性
- 黑马程序员_多态性
- 黑马程序员_多态性和关键字instanceof
- 黑马程序员_多态性编写代码可以提高拓展性
- 黑马程序员_Java多态性
- 黑马程序员-继承性、多态性
- 黑马程序员-JAVA的多态性
- 黑马程序员------Java的多态性
- 黑马程序员----类的继承与多态性之“多态性”
- 黑马程序员---面向对象的多态性
- 黑马程序员-OC-继承的多态性
- 黑马程序员——Java之多态性
- 黑马程序员_枚举
- 黑马程序员_多线程
- 黑马程序员_反射
- 黑马程序员_泛型
- 黑马程序员_注解
- 黑马程序员_注解
- Oracle中出现Ora-00054该怎么处理,V$locked_object和V$session的用法
- TS流的基本概念
- secureCRT下的串口不能输入
- 解决GPG error: The following signatures couldn't be verified because the public key is not available
- Ubuntu下使用Mysql
- 黑马程序员_多态性
- 开发者所需要知道的iOS7 SDK新特性
- 创建一个进程来执行另一个程序
- Mysql查询按照某字段指定顺序排序
- nginx做静态文件下载服务器
- 获取正在运行的桌面包名
- js数据验证
- unity 遮挡剔除 和烘赔参数
- 六旬老汉14年两次失独 听闻女儿溺亡瘫倒(图)