<二> 多态

   面向对象程序设计中的另一个重要概念是多态性。在运行时,可以通过指向基类的指针来调用实现派生类中的方法。可以把一组对象放到一个数组中,然后调用它们的方法,在这种场合下,多态性的作用就体现出来了,这些对象不必是相同的对象。当然,如果它们都继承自某个类,可以把这些类都放到一个数组中。如果这些对象都有同名方法,就可以调用每个对象的同名方法。

   同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果,这就是多态性。多态性通过派生类重载基类中的虚函数型方法来实现

   在C#中支持两种类型的多态性:

 (1)编译时的多态性:编译时的多态性是通过重载来实现的。对于非虚成员来说,系统在编译时,根据传递的参数、返回的类型等信息决定实现何种操作。

 (2)运行时的多态性:运行时的多态性就是指直到系统运行时,才根据实际情况决定实现何种操作。C#中,运行时的多态通过虚成员实现。

   编译时的多态性为我们提供了运行速度快的特点,而运行时的多态性则带来了高度灵活和抽象的特点。

 

1、虚方法的重载

   在类的方法前加上关键字virtual,则该方法被称为虚方法。通过对虚方法的重载,实现在程序运行过程中确定调用的方法。需要注意的是这里所讲的重载与前面所讲的通过参数类型与参数个数的不同实现重载是不同的。

虚方法的重载实例1:

using System;

using System.Collections;

namespace 笔记

{

    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"); }

    }

    public class Test

    {

        public static void MMain()

        {

            B b = new B();

            A a = b;

            a.F();

            b.F();

            a.G();

            b.G();

        }

    }

}

程序运行结果:

A.F

B.F

B.G

B.G

   在A在定义了提供了非虚方法F和虚方法G,派生类B则对方法F实现覆盖,对虚方法G实现了虚方法的重载。“A a=b”实际上a仍旧是一个b对象。

 

虚方法的重载实例2:

using System;

using System.Collections;

namespace 笔记

{

    //定义基类Shape

    public class Shape

    {

        protected string Color;

        public Shape()

        { ;}

        public Shape(string Color)

        {

            this.Color = Color;

        }

        public string GetColor()

        {

            return Color;

        }

        public virtual double GetArea() //虚方法

        {

            return 0.0;

        }

    }

 

    //定义Circle类,从Shape类中派生

    public class Circle : Shape

    {

        private double Radius;

        public Circle(string Color, double Radius)

        {

            this.Color = Color;

            this.Radius = Radius;

        }

        public override double GetArea() //重载虚方法

        {

            return System.Math.PI * Radius * Radius;

        }

    }

 

    //派生类Rectangular,从Shape类中派生

    public class Rectangular : Shape

    {

        protected double Length, Width;

        public Rectangular(string Color, double Length, double Width)

        {

            this.Color = Color;

            this.Length = Length;

            this.Width = Width;

        }

        public override double GetArea() //重载虚方法

        {

            return Length * Width;

        }

        public double PerimeterIs()

        {

            return (2 * (Length + Width));

        }

    }

 

    //派生类Square,从Rectangular类中派生

    public class Square : Rectangular

    {

        public Square(string Color, double Side)

            : base(Color, Side, Side)

        { ;}

    }

    public class Test

    {

        public static void MMain()

        {

            Circle Cir = new Circle("orange", 3.0);

            Console.WriteLine("Cirlle Color is {0},Circle area is {1}", Cir.GetColor(), Cir.GetArea());

            Rectangular Rect = new Rectangular("red", 13.0, 2.0);

            Console.WriteLine("Rectangular Color is {0},Rectangular area is {1},Rectangular Perimeter is {2}", Rect.GetColor(), Rect.GetArea(), Rect.PerimeterIs());

            Square Squ = new Square("green", 5.0);

            Console.WriteLine("Square Color is {0},Square Area is {1},Square Perimeter is {2}", Squ.GetColor(), Squ.GetArea(), Squ.PerimeterIs());

            Shape Shp = Cir;

            Console.WriteLine("Circle area is {0}", Shp.GetArea());

            Shp = Rect;

            Console.WriteLine("Rectangular area is {0}", Shp.GetArea());

        }

    }

}

程序运行结果:

Cirlle Color is orange,Circle area is 28.2743338823081

Rectangular Color is red,Rectangular area is 26,Rectangular Perimeter is 30

Square Color is green,Square Area is 25,Square Perimeter is 20

Circle area is 28.2743338823081

Rectangular area is 26

 

2、抽象类与抽象方法

   抽象类是一种特殊的基类,它不能被实例化,只能作为基类,由其他类继承。抽象类的定义使用关键字abstract。如将Spahe类定义为抽象类:

   public abstract class Shape

   {

     

    }

   在抽象类中也可以使用关键字abstract定义抽象方法,要求所有的派生非抽象类都要重载实现抽象方法。引入抽象方法的原因在于抽象类本身是一种抽象的概念,有的方法并不要具体的实现,而是留下来让派生类来重载实现。

   Shape类中的GetArea方法本身没什么具体的意义,而只有用于派生类Circle类和Rectangular才可以计算具体的面积。

   抽象方法定义为:public abstract double GetArea();

   则派生类重写实现为:public override double GetArea() { … }

 

抽象类和抽象方法的实例:

using System;

using System.Collections;

namespace 笔记

{

    //定义抽象基类Shape

    public abstract class Shape

    {

        protected string Color;

        public Shape()

        { ;}

        public Shape(string Color)

        {

            this.Color = Color;

        }

        public string GetColor()

        {

            return Color;

        }

        public abstract double GetArea(); //抽象方法

    }

 

    //定义Circle类,从Shape类中派生

    public class Circle : Shape

    {

        private double Radius;

        public Circle(string Color, double Radius)

        {

            this.Color = Color;

            this.Radius = Radius;

        }

        public override double GetArea() //重载抽象方法

        {

            return System.Math.PI * Radius * Radius;

        }

    }

 

    //派生类Rectangular,从Shape类中派生

    public class Rectangular : Shape

    {

        protected double Length, Width;

        public Rectangular(string Color, double Length, double Width)

        {

            this.Color = Color;

            this.Length = Length;

            this.Width = Width;

        }

        public override double GetArea() //重载抽象方法

        {

            return Length * Width;

        }

        public double PerimeterIs()

        {

            return (2 * (Length + Width));

        }

    }

 

    //派生类Square,从Rectangular类中派生

    public class Square : Rectangular

    {

        public Square(string Color, double Side)

            : base(Color, Side, Side)

        { ;}

    }

    public class Test

    {

        public static void MMain()

        {

            Circle Cir = new Circle("orange", 3.0);

            Console.WriteLine("Cirlle Color is {0},Circle area is {1}", Cir.GetColor(), Cir.GetArea());

            Rectangular Rect = new Rectangular("red", 13.0, 2.0);

            Console.WriteLine("Rectangular Color is {0},Rectangular area is {1},Rectangular Perimeter is {2}", Rect.GetColor(), Rect.GetArea(), Rect.PerimeterIs());

            Square Squ = new Square("green", 5.0);

            Console.WriteLine("Square Color is {0},Square Area is {1},Square Perimeter is {2}", Squ.GetColor(), Squ.GetArea(), Squ.PerimeterIs());

        }

    }

}

程序运行结果:

Cirlle Color is orange,Circle area is 28.2743338823081

Rectangular Color is red,Rectangular area is 26,Rectangular Perimeter is 30

Square Color is green,Square Area is 25,Square Perimeter is 20

 

3、密封类和密封方法

   密封类是一种不能被其他类继承的类,使用sealed关键字定义。

   如果Rectangular类定义为密封类:

   public sealed Rectangular:Shape

   {

    

    }

   这样Rectangular类的派生类Square就必须删除,否则,就会出错。

   如果类方法声明包含sealed修饰符,称该方法为密封方法。类的实例方法声明包含sealed修饰符,则必须同时使用override修饰符。使用密封方法可以防止派生类进一步重写该方法。如果将圆形Circle类的GetArea方法定义为密封类,必须先将Shape类GetArea方法定义为虚方法:

   public virtual double GetArea()

   {

     

    }

   然后在Circle类中实现密封方法:

   public sealed override double GetArea()

   {

     

    }

   由上面可知:密封方法必须是虚方法的重写。(即是在重写一个虚方法时,在override关键字前面加上sealed关键字,该重写的方法就成了密封方法)

作者: 聚拓互联 发表于 2011-05-29 00:42 原文链接

推荐.NET配套的通用数据层ORM框架:CYQ.Data 通用数据层框架