继承,封装,多态是面向对象的最重要的3个特点.其中多态这个特性比较难理解.多态我比较喜欢的一种解释是:通过继承实现的不同对象,调用相同的方法,产生不同的执行结果.
C#支持两种类型的多态,编译时的多态和运行时的多态。
编译时的多态:
编译时的多态是通过重载来实现的,对于非虚的成员来说,系统在编译时,根据传递的参数类型,个数以及返回类型的不同决定实现不同的操作.
重载:
public int Sum(int x,int y)
public int Sum(int x,int y,int z)
public double Sum (Double x,Double y)
重载特点:
- 方法名称必须相同
- 参数列表必须不同
- 返回值类型可以不同
运行时的多态:
运行时的多态是指系统直到运行时,才根据实际情况实现何种操作.
运行时的多态可以通过virtual-override(虚成员覆盖实现)以及abstract-override(抽象方法覆盖实现)两种方式来实现.
例如:
namespace ConsoleApplication1
{
abstract class A
{
public void F()
{
Console.WriteLine("A.F");
}
public virtual void G()
{
Console.WriteLine("A.G");
}
public abstract void H();
}
class B : A
{
public new void F()
{
Console.WriteLine("B.F");
}
public override void G()
{
Console.WriteLine("B.G");
}
public override void H()
{
Console.WriteLine("B.H");
}
}
class Program
{
static void Main(string[] args)
{
B b = new B();
A a = new B();
b.F();
b.G();
b.H();
a.F();
a.G();
a.H();
Console.Read();
}
}
}
上面的举例注意的知识点:
C#只能继承单个类,而可以继承多个接口.
抽象方法只能定义在抽象类中,抽象类不能被实例化.
运行结果:
B.F
B.G
B.H
A.F
B.G
A.H
对于对象b输出的结果很容易理解
那么A a=new B() 到底是A类的实例化对象还是B类的实例化对象,可以这样理解
a是披着A皮的B,记住一点,对于a,在子类中没有通过override覆盖的方法,它调用自身的实现,对于在子类中通过override覆盖的方法,它调用子类的实现.
如果代码稍微修改一下:
namespace ConsoleApplication1
{
abstract class A
{
public void F()
{
Console.WriteLine("A.F");
}
public virtual void G()
{
Console.WriteLine("A.G");
}
public abstract void H();
}
class B : A
{
public new void F()
{
Console.WriteLine("B.F");
}
public void G()
{
Console.WriteLine("B.G");
}
public override void H()
{
Console.WriteLine("B.H");
}
}
class Program
{
static void Main(string[] args)
{
B b = new B();
A a = new B();
b.F();
b.G();
b.H();
a.F();
a.G();
a.H();
Console.Read();
}
}
}
那么a.G();将调用自身的实现,输出A.G
通过override实现覆写注意的几点
- 只有虚方法和抽象方法才能被覆写
- 子类和基类中的方法必须具有相同的方法名称,参数个数,参数类型以及返回值类型.
总结:
- 编译时的多态使运行速度更快,就像const编译时解析.
- 运行时的多态带来了高度灵活以及抽象的特点.