zoukankan      html  css  js  c++  java
  • C#学习笔记:多态与隐藏,覆盖

    以继承为基础,继承举例:

    public class Person
    {
     
    public void Sayhello()
     
    {
      Console.WriteLine(
    "Hello,I am a person");
     }

    }

    public class Student:Person
    {
    }

    Student类继承与Person类

    我们想改变Student里面继承Person的SayHello()方法,使其具有自己的特性.这里使用new关键字.

    public class Person
    {
     
    public void SayHello()
     
    {
      Console.WriteLine(
    "Hello,I am a person");
     }

    }

    public class Student:Person
    {
     
    new public void SayHello()
     
    {
      Console.WriteLine(
    "hello,I am a student");
     }

    }


    public class Test
    {
     
    static void Main()
     
    {
      Person aPerson
    =new Person();
      Student aStudent 
    = new aStudent();
      
      aPerson.SayHello();
      aStudent.SayHello();
     }

    }



    输出:
    hello,I am a person
    hello,I am a student

    这个过程在Inside C#-MSPress称为override:
    you want to derive a class from (Person) and you want to override the (SayHello) method to do something specific to the derived class. To do this, you need to use the new keyword with the derived class's method definition.
    但在翻译成中文时,称为:隐藏.


    多态(Polymorphism)

    当使用关键字new来override基类的方法时,程序运行很尽人意.
    (Method overriding with the new keyword works fine if you have a reference to the derived object)

    语言的每个概念的产生都是需要理由的(你不防问问自己为什么c#会有Class,Method...这些概念),这里,我们要问:
    为什么会有多态这个概念的出现?有什么用处呢?
    (看了很多.NET书籍,好像没有这样来解释各个概念的)

    从实际出发,看下面例子:Student,Teacher都是Person,在实际应用中,我们需要把所有Person的派生类组装(populate)到一个数组里面,这个数组的数据类型必定是Person了,而且,通过这个Person[]数组来重新调用数组元素(Person的派生类)的SayHello方法.

    public class Person
    {
     
    public void SayHello()
     
    {
      Console.WriteLine(
    "Hello,I am a person");
     }

    }

    public class Student:Person
    {
     
    new public void SayHello()
     
    {
      Console.WriteLine(
    "hello,I am a student");
     }

    }

    public class Teacher:Person
    {
     
    new public void SayHello()
     
    {
      Console.WriteLine(
    "hello,I am a teacher");
     }

    }

    public class Test
    {
     
    private static Person[] persons=new Person[2];
     
    static void Main()
     
    {
      persons[
    0]=new Student();
      persons[
    1]=new Teacher();
     
      persons[
    0].SayHello();
      persons[
    1].SayHello();
     }

    }


    输入结果:
    hello,I am a person
    hello,I am a person

    (Obviously, this is not what we wanted)对,在实际应用中,我们不希望出现这种结果.
    希望输出:
    hello,I am a student
    hello,I am a teacher

    上面的例子,为什么会出现我们所不希望的结果呢?
    看看Inside C#的解释:

    What happened here is an example of a phenomenon called early binding. When the code was compiled, the C# compiler looked at the call to Persons[].SayHello() and determined the address in memory that it would need to jump to when the call is made. In this case, that would be the memory location of the Person.SayHello method.
    Take a look at the following MSIL that was generated from the Test application, and specifically take note of line IL_0014 and the fact that it explicitly calls the Employee.CalculatePay method:

    ....
    IL_0014:  call       instance void Employee::CalculatePay()

    ....

    That call to the (Person.SayHello) method is the problem. What we want instead is for late binding to occur. Late binding means that the compiler does not select the method to execute until run time. To force the compiler to call the correct version of an upcasted object's method, we use two new keywords: virtual and override. The virtual keyword must be used on the base class's method, and the override keyword is used on the derived class's implementation of the method.

    public class Person
    {
     virtual public void SayHello()
     {
      Console.WriteLine("Hello,I am a person");
     }
    }
    public class Student:Person
    {
     override public void SayHello()
     {
      Console.WriteLine("hello,I am a student");
     }
    }
    public class Teacher:Person
    {
     override public void SayHello()
     {
      Console.WriteLine("hello,I am a teacher");
     }
    }
    public class Test
    {
     private static Person[] persons=new Person[2];
     static void Main()
     {
      persons[0]=new Student();
      persons[1]=new Teacher();
     
      persons[0].SayHello();
      persons[1].SayHello();
     }
    }

    Before running this application, let's take a peek at the IL code that's generated, this time noting that line IL_0014 uses the MSIL opcode callvirt,which tells the compiler that the exact method to be called won't be known until run time because it's dependent on which derived object is being used:

    .....
    IL_0014:  callvirt   instance void Employee::CalculatePay()
    .....


    输出为:
    hello,I am a student
    hello,I am a teacher

    要深刻理解这个过程,必须搞明白什么是"Early Binding&Late Binding","run time",具有"编译原理"相关知识.
    本人还没有学习"编译原理"以及"汇编程序",这一点还是没有搞彻底,不再引用这方面的资料,可以查阅MSDN


    BTW,我们还可以用类型转换来得到我们想要的:
    class Test修改为:

    public class Test
    {
     
    private static Person[] persons=new Person[2];
     
    static void Main()
     
    {
      persons[
    0]=new Student();
      persons[
    1]=new Teacher();
     
      Student s
    =new Student();
      Teacher t
    =new Teacher();

      s
    =(Student)persons[0];
      t
    =(Teacher)Persons[1];

      s.SayHello();
      t.SayHello();

     }

    }



    ===========================================
    以上文章参考(部分字句为直接翻译)
    [1]Inside C# / Tom Archer.(Microsoft Press)
    [2]Visual C# .NET:A Gudie for VB6 Develops/Brand Maiani,James Still...(Wrax)

  • 相关阅读:
    ASP.NET2.0中GridView加入CheckBox实现全选!
    恢复误删数据(SQL Server 2000)--Log Explorer
    url传递中文的解决方案总结
    JavaScript : Tip提示框。
    合并GridView中某列相同信息的行
    ASP.NET 2.0服务器控件与form runat=server标记 !!
    实现天气预报类···························
    正则抓取SINA天气预报数据!!!
    ASP.NET 2.0中将 GridView 导出到 Excel 文件中
    GridView控件修改、删除示例(修改含有DropDownList控件)
  • 原文地址:https://www.cnblogs.com/caca/p/27842.html
Copyright © 2011-2022 走看看