7.C# 多态的实现
C# 多态的实现
封装、继承、多态,面向对象的三大特性,前两项理解相对容易,但要理解多态,特别是深入的了解,对于初学者而言可能就会有一定困难了。我一直认为学习OO的最好方法就是结合实践,封装、继承在实际工作中的应用随处可见,但多态呢?也许未必,可能不经意间用到也不会把它跟“多态”这个词对应起来。在此抛砖引玉,大家讨论,个人能力有限,不足之处还请指正。
之前看到过类似的问题:如果面试时主考官要求你用一句话来描述多态,尽可能的精炼,你会怎么回答?当然答案有很多,每个人的理解和表达不尽相同,但我比较趋向这样描述:通过继承实现的不同对象调用相同的方法,表现出不同的行为,称之为多态。
例1:
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:
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:
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:
代码
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一样地实现多态,包括多层继承也是一样的。不同之处在于,包含虚拟方法的类可以被实例化,而包含抽象方法的类不能被实例化。
转自https://www.cnblogs.com/ldyblogs/p/override.html
7.C# 多态的实现的更多相关文章
- Java中的多态
1.多态:具有表现多种形态的能力的特征 父类: public abstract class Animal {public abstract void Say();} 子类: public class ...
- C# 工厂模式+虚方法(接口、抽象方法)实现多态
面向对象语言的三大特征之一就是多态,听起来多态比较抽象,简而言之就是同一行为针对不同对象得到不同的结果,同一对象,在不同的环境下得到不同的状态. 实例说明: 业务需求:实现一个打开文件的控制台程序的d ...
- C#非常重要基础之多态
前几天看了一位同志的博客,写的是关于他自己去支付宝面试的经历.过程大体是这样的:问答的时候,前面部分,作者都应答如流,说起自己经验如何之丰富,最后面试官问了作者一个问题:请简述多态的概念和作用.结果这 ...
- C++多态详解
多态是面向对象的程序设计的关键技术.多态:调用同一个函数名,可以根据需要但实现不同的功能.多态体现在两个方面,我们以前学过的编译时的多态性(函数重载)和现在我们这一章将要学习的运行时的多态性(虚函数) ...
- 【那些年关于java多态应用】
1.多态:具有表现多种形态的能力的特征 父类: public abstract class Animal { public abstract void Say();} 子类: public class ...
- JAVA多态
多态是指当系统A访问系统B的服务时,系统B可以通过多种方式来提供服务,而这一切对系统A是透明的.比如动物园的饲养员能够给各种各样的动物喂食.下图显示了饲养员Feeder,食物Food和动物Animal ...
- C#多态“说来也说”——逻辑层BLL中的多态使用
本文版权归博客园和作者吴双本人共同所有.欢迎转载,转载和爬虫请注明原文地址 http://www.cnblogs.com/tdws/p/5861842.html 昨天晚上,有个朋友说学了好久,依然没搞 ...
- java多态的理解
面向对象语言中的类有三个特征,封装.继承.多态.封装与继承很好理解,那什么是多态呢? 1.什么是多态? 多态的定义:指允许不同类的对象对同一消息做出响应.即同一消息可以根据发送对象的不同而采用多种不同 ...
- java中如何实现多态
复习基础知识 多态,就是重载和重写.重载发生在一个类中.重写发生在子类,意思就是子类重写父类相同名称的方法.刚学语言有的东西,不必搞得那么清楚,只有知道怎么用就行了,有的问题你要想真正把它搞得很懂,短 ...
- OC多态
要点: 1.多种形态,引用的多种形态对于一个引用变量,可以指向任何类的对象.对于一个父类的引用(类与类之间有一种继承关系),可以指向子类,也可以指向本类,指向的类型不同.当通过此引用向对象发送消息,调 ...
随机推荐
- 解决ubuntu系统“XXX is not in the sudoers file”错误
用adduser新建的用户,当时只输入了一个用户名,没做其它操作,这样就建立了一个normal用户.在执行sudo vim hadoop-env.sh时,报“*** is not in the sud ...
- ATM JAVA实现 部分代码
package score;//信1705-2 20173600 王重阳 import java.util.Scanner; public class Main { public static voi ...
- Hive日志(Hive Logging)--hive GettingStarted翻译
Hive uses log4j for logging. By default logs are not emitted to the console by the CLI. The default ...
- 函数调用堆栈及活动记录 堆栈溢出 stack overflow
小结: 1.当被调函数返回主调函数时,被调函数的 活动记录-activation record / 堆栈帧-stack frame 被 弹出-popping 程序执行栈-program executi ...
- ACM:油田(Oil Deposits,UVa 572)
/* Oil Deposits Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Tot ...
- 介绍一款jquery ui组件gijgo(含tree树状结构、grid表格),特点:简易、文档全清晰易懂、示例代码
http://gijgo.com gijgo组件 特点:简易.文档全-虽然是英文的但是清晰易懂可读性强.含示例代码(后端直接用原生.Net C# MVC的哦!非常合.Net开发胃口),网站网速快, ...
- Flink - FlinkKafkaProducer010
https://ci.apache.org/projects/flink/flink-docs-release-1.3/dev/connectors/kafka.html 使用的方式, DataStr ...
- tp5, laravel, yii2我该选择哪个
为什么写这篇文章 我个人有一个技术群,里面学什么框架的都有,经常会有人问 某某功能 在 哪个框架怎么实现,用什么框架实现更好,说道这里我大家讲一个同类型问题的笑话 某女:你能让这个论坛的人都吵起来,我 ...
- pyinstaller-打包python程序为exe文件
pyinstaller ---转载文章 视频:https://www.bilibili.com/video/av21670971/ PyInstaller可以用来打包python应用程序,打包完的程序 ...
- linux内存不足,swap交换分区创建
为什么需要swap 根 据Redhat公司的建议,Linux系统swap分区最适合的大小是物理内存的1-2倍.不过Linux上有些软件对swap分区得需求较大,例如要顺 利执行Oracle数据库软件, ...