首先理解一下什么叫多态。同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果,这就是多态性。
多态性通过派生类覆写基类中的虚函数型方法来实现。
多态性分为两种,一种是编译时的多态性,一种是运行时的多态性。
编译时的多态性:编译时的多态性是通过重载来实现的。对于非虚的成员来说,系统在编译时,根据传递的参数、返回的类型等信息决定实现何种操作。
运行时的多态性:运行时的多态性就是指直到系统运行时,才根据实际情况决定实现何种操作。C#中运行时的多态性是通过覆写虚成员实现。
下面我们来分别说明一下多态中涉及到的四个概念:重载,覆写,虚方法和抽象方法。
重载和覆写的区别:
重载
类中定义的方法的不同版本
public int Calculate(int x, int y)
public double Calculate(double x, double y)
特点(两必须一可以)
方法名必须相同
参数列表必须不相同
返回值类型可以不相同
覆写
子类中为满足自己的需要来重复定义某个方法的不同实现。
通过使用override关键字来实现覆写。
只有虚方法和抽象方法才能被覆写。
要求(三相同)
相同的方法名称
相同的参数列表
相同的返回值类型
例:
public class Test
{
public int Calculate(int x, int y)
{
return x + y;
}
public double Calculate(double x, double y)
{
return x + y;
}
}
首先看这个类,我们在同一个类中满足了重载的三个特点,方法名必须相同Calculate;参数列表必须不相同第一个方法的两个参数类型为int类型,第二个方法的两个参数类型为double类型;返回值类型可以不相同一个返回值类型为int,另一个返回值类型为double。
然后我们在客户程序中调用这两个方法。

这时候我们发现智能提示里提示这个方法已经被重载过一次了。这样我们就可以根据业务逻辑调用不同的方法来实现不同的业务。


客户端测试程序:
Test t = new Test();
int x;
int y;
Console.WriteLine("Please input an integer.\n");
x = Convert.ToInt32(Console.ReadLine());
Console.WriteLine("Please input another integer.\n");
y = Convert.ToInt32(Console.ReadLine());
Console.WriteLine("Test class Calculate method result.\n");
int result1 = t.Calculate(x,y);
Console.WriteLine("int x + int y = {0}\n",result1.ToString());
double a;
double b;
Console.WriteLine("Please input an double.\n");
a = Convert.ToDouble(Console.ReadLine());
Console.WriteLine("Please input another double.\n");
b = Convert.ToDouble(Console.ReadLine());
Console.WriteLine("Test class Calculate method result.\n");
double result2 = t.Calculate(a,b);
Console.WriteLine("double x + double y = {0}\n",result2.ToString());
Console.ReadLine();
执行结果为:
下面来看一看覆写,我们将基类(父类)作一下修改
public class Test
{
public virtual int Calculate(int x, int y)
{
return x + y;
}
public virtual double Calculate(double x, double y)
{
return x + y;
}
}
派生类(子类)
public class TestOverride : Test
{
public override int Calculate(int x, int y)
{
return x * y;
}
public override double Calculate(double x, double y)
{
return x * y;
}
}
这是我们会在客户端的测试程序中发现,我们既可以访问到覆写后的方法也能访问到覆写前基类的方法,显示被重载3次,其中两次是被覆写的





客户端测试程序
TestOverride t = new TestOverride();
int x;
int y;
Console.WriteLine("Please input an integer.\n");
x = Convert.ToInt32(Console.ReadLine());
Console.WriteLine("Please input another integer.\n");
y = Convert.ToInt32(Console.ReadLine());
Console.WriteLine("Test class Calculate method result.\n");
int result1 = t.Calculate(x,y);
Console.WriteLine("int x * int y = {0}\n",result1.ToString());
double a;
double b;
Console.WriteLine("Please input an double.\n");
a = Convert.ToDouble(Console.ReadLine());
Console.WriteLine("Please input another double.\n");
b = Convert.ToDouble(Console.ReadLine());
Console.WriteLine("Test class Calculate method result.\n");
double result2 = t.Calculate(a,b);
Console.WriteLine("double x * double y = {0}\n",result2.ToString());
Console.ReadLine();
执行结果为:

这里还有一个需要提的地方就是在子类如果需要访问父类的方法可以使用base关键字,例如:
public class TestOverride : Test
{
public override int Calculate(int x, int y)
{
return base.Calculate (x, y);
}
public override double Calculate(double x, double y)
{
return base.Calculate (x, y);
}
}
这样我们在客户程序进行访问继承Test类TestOverride类的方法时返回的还是加法运算的结果。

我们来对重载和覆写作一个比较
|
Override覆写
|
Overload重载
|
位置
|
存在于继承关系的类中
|
存在于同一类中
|
方法名
|
相同
|
相同
|
参数列表
|
相同
|
必须不同
|
返回值
|
相同
|
可以不相同
|
最后再来介绍一下虚方法和抽象方法
虚方法
声明使用virtual关键字。
调用虚方法,运行时将确定调用对象是什么类的实例,并调用适当的覆写的方法。
虚方法可以有实现体。
抽象方法
必须被派生类覆写的方法。
可以看成是没有实现体的虚方法。
如果类中包含抽象方法,那么类就必须定义为抽象类,不论是否还包含其他一般方法。
关于虚方法,上面我们做了一些实验,下面来看一个关于抽象方法的例子。
例:
public class TestOverride : Test
{
public abstract int Calculate(int x, int y);
public abstract double Calculate(double x, double y);
}
在编译的时候会出现一个错误

要求抽象方法必须被报刊在抽象类中,我们作如下修改
Public abstract class TestOverride : Test
{
public abstract int Calculate(int x, int y);
public abstract double Calculate(double x, double y);
}
这时满足了抽象方法的要求,即可编译通过

同样我们还可以对其进行覆写,其实这里的覆写就是我们所说的对于一个抽象的具体实现。如上面离子所示,我们先用一个抽象类定义了一个测试类并在其中定义了这个类可以做两个整数或者实数的计算操作,至于具体做什么样的计算和怎么计算并没有定义,只是声明我能做这些事,然后在它的子类(一个具体的类)中实现了他的定义,我们要做的是乘法计算。我们还可以通过另一个具体的类还定义我们可能要做的不是乘法计算而是加法计算。代码如下:
public class TestAdd : Test
{
public override int Calculate(int x, int y)
{
return x + y;
}
public override double Calculate(double x, double y)
{
return x + y;
}
}
这样我们就实现了用抽象类来定义操作,用具体的类还根据不同情况实现不同的操作。关于这一点就引出了我们设计模式中创建型模式中的工厂方法、建造者、抽象工厂方法等(这些是我暂时学到的模式),如果大家想了解这些知识可以参考TerryLee的设计模式系列文章,很经典。
到此为止我们介绍了C#中多态性涉及的几个概念,希望对大家的在以后代码结构设计上能有所帮助:)
在这里牢骚几句,现在的项目中变化是一件很平常的事,我们设计的软件就是要适应这种经常的变化,将项目中的一些变化点封装起来,在业务发生变化的时候我们能很轻松的应对这种变化。一个软件的必定会经过它生命周期中的各个部分并最后走向死亡,但是我们可以在设计中通过使软件有能力来应对这些变化来使它的生存期长一些,会为我们带来更多的价值(哈哈,这些其实就是设计模式所要达到的一些目的)。
希望大家能从此文中得到一些收获,谢谢:)
长久以来,多态性一直困扰着我,虽然我知道是怎么回事,但说不出来,也许就是只能意会,不能言传吧,
通过继承,一个类可以用作多种类型 :可以用作它自己的类型,也可以用作基类型,或者在实现接口时用作任何接口类型,这就成为多态性。
C# 中每种类型都是多态的,类型可用作他们自己的类型或用作Object的实例,因为任何类型都自动将Object当作基类型。
多态性不仅对派生类很重要,对基类也很 重要,在任何情况下,使用基类实际上是都可能是在使用已经强制转化成基类类型的派生类对象,基类的设计者预测到其基类中可能会在派生类中发生更改的方面。
当派生类从基类继承时,它会获得所有基类的方法,属性等,若要改变基类的和行为,有两种方法:一是使用新的派生成员替代基成员,二是重写基类中的虚拟成员。
使用新的派生成员替换基成员使用关键字new,如果基类定义了一个方法或字段,则new关键字创建该方法或字段的新定义,new关键字要放在返回值类型之前。
如:
class BaseClass
{
public void BaseMethod()
{ }
}
class DerivedClass : BaseClass
{
public new void BaseMethod()
{ }
}
使用 new 关键字时,调用的是新
的类成员而不是已被替换的基类成员。这些基类成员称为隐藏成员。如果将派生类的实例强制转换为基类的实例,就仍然可以调用隐藏类成员。
为了使派生类的实例完全接替来自基类的类成员,基类必须将该成员声明为虚拟的。这是通过在该成员的返回类型之前添加 virtual 关键字来实现的。然后,派生类可以选择使用 override 关键字而不是 new,将基类实现替换为它自己的实现。
如:
public class BaseClass
{
public virtual int WorkProperty
{
get { return 0; }
}
}
public class DerivedClass : BaseClass
{
public override int WorkProperty
{
get { return 0; }
}
}
字段不能是虚拟的,只有方法、属性、事件和索引器才可以是虚拟的。当派生类重写某个虚拟成员时,即使该派生类的实例被当作基类的实例访问,也会调用该成员
使用虚拟方法和属性可以预先计划未来的扩展。由于在调用虚拟成员时不考虑调用方正在使用的类型,所以派生类可以选择完全更改基类的外观行为。
无论在派生类和最初声明虚拟成员的类之间已声明了多少个类,虚拟成员都将永远为虚拟成员
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/luqinghua/archive/2007/04/03/1550262.aspx
分享到:
相关推荐
本文将深入探讨C#中的多态性,并通过具体的示例来帮助读者更好地理解和应用这一特性。 #### 1. 多态性的定义 多态性是指允许变量、函数或对象采用多种类型的特性。在C#中,可以通过以下几种方式实现多态: - **...
### C#中的多态性详解 #### 一、多态性的概念 在C#中,多态性(Polymorphism)是一种重要的面向对象编程特性,它允许子类重写或扩展父类的方法,从而实现同一接口的不同实现方式。多态性意味着一个接口可以具有...
多态是指一个行为具有多个不同表现形式的能力,在C#中通过多态性的检测时机可以分为静态多态性和动态多态性 静态多态性:函数重载和运算符重载 动态多态性:抽象方法、重写方法、隐藏方法 二:函数重载(overlode) ...
本实验报告旨在深入理解和实践C#中的多态性,通过设计一个银行卡类(BankCard)及其派生类(ForeignCard,LimitedCard),以模拟实际的银行系统操作。 一、实验目的 1. 理解面向对象编程中的继承概念,掌握如何在C#...
深入浅析C#静态多态性与动态多态性 多态性是面向对象编程的一种基本概念,指的是同一个对象在不同的情况下可以有不同的行为。C#语言提供了两种多态性:静态多态性和动态多态性。 静态多态性是指在编译时,函数和...
描述虚函数与飞虚函数的区别,以及多态的使用
综上所述,这个"C#多态性实例,向基类构造函数传递参数"的示例展示了如何在C#中利用多态性、继承和构造函数来创建灵活、可扩展的代码结构。通过理解和应用这些概念,开发者可以编写出更高效、更具维护性的软件系统。
在C#应用程序开发中,多态性是一项核心概念,它允许不同的对象对同一行为做出不同的响应,从而展现出不同的行为特征。多态性是面向对象编程的三大特性之一,另外两个是封装和继承。多态性使得代码更具通用性和可扩展...
一、List对象中的T是值类型的情况(int 类型等) 对于值类型的List直接用以下方法就可以复制: List<T> oldList = new List(); oldList.Add(..); List<T> newList = new List(oldList); 二、List对象中的T是引用...
前两天写了篇博文 《浅谈C# WinForm中实现基于角色的权限菜单》,许多过路的朋友都问着要源码,现在我还是抽空把完整实现源码抽离出来给大家参考一下。此资源对应的博文地址:...
第一种:编译时的多态性,直接这样说不知道说啥?程序执行过程主要分为三步:编译,链接,运行。...C#运行时的多态性通过虚方法实现。在类方法声明加上了virtual修饰符,称为虚方法,反之为非虚方法
书中会详细介绍如何创建类、实例化对象,以及如何通过继承和多态性实现代码复用和灵活性。 3. **异常处理**:学习如何使用try-catch语句捕获和处理运行时可能出现的错误,提高程序的健壮性。 4. **集合与泛型**:...
在C#中,多态性主要体现在两个方面:编译时多态和运行时多态。编译时多态主要是通过方法重载(Overloading)实现,而运行时多态则依赖于方法重写(Overriding)和接口实现。 二、方法重载 方法重载允许我们在同一个...
此外,可能会讲解面向对象编程的基础,如类、对象、封装、继承和多态性。HeadFirst系列的特色就是通过实际的案例,让读者理解这些抽象的编程概念。 第三章可能会讨论数组和集合,这是处理多个数据项的重要工具。...
在这一系列“跳水在面向对象编程”的这篇...抽象类起到多态性和继承一个不同的和非常有趣的角色。我们将讨论抽象类与我们的动手实验和理论作为解释什么输出我们得到的所有方面。我们也将列出下来点,记得在文章的结尾。
同时,也会涉及继承、封装和多态性等面向对象的三大特性,这些都是C#实现代码复用和模块化的重要手段。 在程序设计中,错误处理和异常处理是不可或缺的部分。C#提供了异常处理机制,通过try-catch-finally语句块来...
在上一版的类似资料中,有一个小小的缺陷,得手动调整Label的大小,这一版中的Label可自动调整大小,以实现一个双态按钮,即按钮有两个状态:平常态和凹下态。此种按钮不仅起到给用户提供界面当前焦点的作用,还可以...
3. **接口与抽象类**:通过HFC#_ch9.zip,可能讨论了接口(Interface)和抽象类(Abstract Class)的使用,它们在实现多态性和设计模式中的作用。 4. **数组与集合**:HFC#_ch4.zip可能涉及数组和集合的使用,包括...
了解如何创建类、对象,以及如何利用接口和抽象类实现多态性,是C#学习的重要环节。 3. **泛型**:泛型提供了一种在代码中创建可重用组件的方法,允许开发者定义可以处理多种数据类型的类和方法,增强了代码的灵活...