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)

posted @ 2004-07-27 23:10  cacard  阅读(1527)  评论(1编辑  收藏  举报