zoukankan      html  css  js  c++  java
  • 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一样地实现多态,包括多层继承也是一样的。不同之处在于,包含虚拟方法的类可以被实例化,而包含抽象方法的类不能被实例化。

  • 相关阅读:
    Android游戏开发22:Android动画的实现J2me游戏类库用于Android开发
    android sqlite SQLiteDatabase 操作大全 不看后悔!必收藏!看后精通SQLITE (第三部分,完整代码)
    使用OGR创建dxf格式矢量数据
    mysql 数据库引擎 MyISAM InnoDB 大比拼 区别
    android sqlite SQLiteDatabase 操作大全 不看后悔!必收藏!看后精通SQLITE (第二部分)
    mysql 更改数据库引擎
    android sqlite SQLiteDatabase 操作大全 不看后悔!必收藏!看后精通SQLITE (第一部分)
    android 数字键盘使用
    MySQL Innodb数据库性能实践
    eclipse : Error while performing database login with the driver null
  • 原文地址:https://www.cnblogs.com/zcwvictor-2012/p/3790084.html
Copyright © 2011-2022 走看看