c#中的多态性
首先理解一下什么叫多态。同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果,这就是多态性。
多态性通过派生类覆盖基类中的虚函数型方法来实现。
多态性分为两种,一种是编译时的多态性,一种是运行时的多态性。
编译时的多态性:编译时的多态性是通过重载来实现的。对于非虚的成员来说,系统在编译时,根据传递的参数、返回的类型等信息决定实现何种操作。
运行时的多态性:运行时的多态性就是指直到系统运行时,才根据实际情况决定实现何种操作。C#中运行时的多态性是通过覆盖虚成员实现。
举例:
using System;
public class DrawingBase
{
public virtual void Draw()
{
Console.WriteLine("I'm just a generic drawing object.");
}
}
public class Line : DrawingBase
{
public override void Draw()
{
Console.WriteLine("I'm a Line.");
}
}
public class Circle : DrawingBase
{
public override void Draw()
{
Console.WriteLine("I'm a Circle.");
}
}
public class Square : DrawingBase
{
public override void Draw()
{
Console.WriteLine("I'm a Square.");
}
}
public class DrawDemo
{
public static int Main(string[] args)
{
DrawingBase[] dObj = new DrawingBase[4];
dObj[0] = new Line();
dObj[1] = new Circle();
dObj[2] = new Square();
dObj[3] = new DrawingBase();
foreach (DrawingBase drawObj in dObj)
drawObj.Draw();
return 0;
}
}
下面我们来分别说明一下多态中涉及到的四个概念:重载,覆盖,虚方法和抽象方法。
4.1 重载 在面对对象这样的高级语言中都允许我们在一个类中定义多个方法名相同、方法间参数个数和参数顺序不同的方法,对于参数个数不同或者参数列表不同的情况我们称之为参数列表不同。需要注意的是这里没有提到方法的返回值。
特点(两必须一可以)
方法名必须相同
参数列表必须不相同
返回值类型可以不相同
public int Calculate(int x, int y)
public double Calculate(double x, double y)
举例:
public class Test
{
public int Calculate(int x, int y)
{
return x + y;
}
public double Calculate(double x, double y)
{
return x + y;
}
}
4.2 覆盖 子类中,为满足自己的需要来重复定义某个方法的不同实现。
定义:通过使用关键字override来覆盖
public override bool abc(...)
注意:只有虚方法和抽象方法才能被覆盖
要求:
*相同的方法名称
*相同的参数列表
*相同的返回值类型
例:
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;
}
}
首先看这个类,我们在同一个类中满足了重载的三个特点,方法名必须相同Calculate;参数列表必须不相同第一个方法的两个参数类型为int类型,第二个方法的两个参数类型为double类型;返回值类型可以不相同一个返回值类型为int,另一个返回值类型为double。
4.3虚方法
当类中的方法声明前加上了virtual修饰符,我们称之为虚方法,反之为非虚。使用了virtual修饰符后,不允许再有static,abstract,或override修饰符。
对于非虚的方法,无论被其所在类的实例调用,还是被这个类的派生类的实例调用,方法的执行方式不变。而对于虚方法,它的执行方式可以被派生类改变,这种改变是通过方法的重载来实现的。
特点:
●声明使用virtual关键字。
●调用虚方法,运行时将确定调用对象是什么类的实例,并调用适当的覆写的方法。
●虚方法可以有实现体。
下面的例子说明了虚方法与非虚方法的区别。
例子:
using System;
class A
{
public void F() { Console.WriteLine("A.F"); }
public virtual void G() { Console.WriteLine("A.G"); }
}
class B : A
{
new public void F() { Console.WriteLine("B.F"); }
public override void G() { Console.WriteLine("B.G"); }
}
class Tese
{
static void Main()
{
B b = new B();
A a = b;
a.F();
b.F();
a.G();
b.G();
}
}
例子中,A类提供了两个方法:非虚的F和虚方法G.类B则提供了一个新的非虚的方法F,从而覆盖了继承的F;类B同时还重载了继承的方
法G.那么输出应该是:
A.F
B.F
B.G
B.G
注意到本例中,方法a.G()实际调用了B.G,而不是A.G.这是因为编译时值为A,但运行时值为B,所以B完成了对方法的实际调用.
4.4抽象类与方法
抽象类具有以下特性:
●抽象类不能实例化。使用override关键字可在派生类中实现抽象方法,经override声明重写的方法,其签名必须与override方法的签名一致。
●抽象类可以包含抽象方法和抽象访问器。
●不能用 sealed 修饰符修改抽象类,这意味着该类不能被继承。
从抽象类派生的非抽象类必须包括继承的所有抽象方法和抽象访问器的实实现。
在方法或属性声明中使用 abstract 修饰符以指示此方法或属性不包含实现。
抽象方法具有以下特性:
●抽象方法是隐式的 virtual 方法。
●只允许在抽象类中使用抽象方法声明。
因为抽象方法声明不提供实实现,所以没有方法体;方法声明只是以一个分号结束,并且在签名后没有大括号 ({ })。例如:
public abstract void MyMethod();
●实现由 overriding 方法提供,它是非抽象类的成员。
●在抽象方法声明中使用 static 或 virtual 修饰符是错误的。
除了在声明和调用语法上不同外,抽象属性的行为与抽象方法一样。
●在静态属性上使用 abstract 修饰符是错误的。
●在派生类中,通过包括使用 override 修饰符的属性声明可以重写抽象的继承属性。
抽象类必须为所有接口成员提供实现。即如果父类被声明为抽象类,并存在未实现的抽象方法,那么子类就必须实现父类中所有的abstract成员,除非该类也是抽象的。
举例:
using System;
using System.Collections.Generic;
using System.Text;
namespace ConsoleApplication1
{
/// <summary>
/// 抽象类hcedar
/// </summary>
abstract class hcedar
{
/// <summary>
/// 抽象方法SayHello
/// </summary>
abstract public void SayHello();
/// <summary>
/// 抽象属性Hello
/// </summary>
abstract public string Hello
{
get;
set;
}
public void SayAbstract()
{
Console.WriteLine("this is a abstract!");
}
}
/// <summary>
/// hcedar2类,继承hcedar
/// </summary>
class hcedar2 : hcedar
{
public string _hello;
/// <summary>
/// Hello属性及其实现
/// </summary>
override public string Hello
{
get
{
return _hello;
}
set
{
_hello = value;
}
}
/// <summary>
/// SayHello方法及其实现
/// </summary>
override public void SayHello()
{
Console.WriteLine(Hello);
}
}
class Program
{
public static void Main()
{
hcedar2 h = new hcedar2();
h.Hello="Hello World!";
h.SayHello();
h.SayAbstract();
}
}
/*结果:
Hello World!
this is a abstract!
请按任意键继续. . .
*/
}