2014-08-27 109 views
1

为了更多地理解多态性,我构建了一个小测试,它返回了意想不到的结果。多态性意想不到的结果

所以这个想法是用虚拟/覆盖关键字覆盖基类的方法,但似乎我不需要这些?

public class Employee 
     { 
      public Employee() 
      { 
       this.firstName = "Terry"; 
       this.lastName = "Wingfield"; 
      } 

      public string firstName { get; set; } 
      public string lastName { get; set; } 

      public void writeName() 
      { 
       Console.WriteLine(this.firstName + " " + this.lastName); 
       Console.ReadLine(); 
      } 
     } 

     public class PartTimeEmployee : Employee 
     { 
      public void writeName() 
      { 
       Console.WriteLine("John" + " " + "Doe"); 
       Console.ReadLine(); 
      } 
     } 
     public class FullTimeEmployee : Employee 
     { 
      public void writeName() 
      { 
       Console.WriteLine("Jane" + " " + "Doe"); 
       Console.ReadLine(); 
      } 
     } 

     static void Main(string[] args) 
     { 
      Employee employee = new Employee(); 
      PartTimeEmployee partTimeEmployee = new PartTimeEmployee(); 
      FullTimeEmployee fullTimeEmployee = new FullTimeEmployee(); 

      employee.writeName(); 
      partTimeEmployee.writeName(); 
      fullTimeEmployee.writeName(); 
     } 
    } 

利用上述我期待的代码导致像这样:

  1. 特里Wignfield
  2. 特里温菲尔德
  3. 特里温菲尔德

但代替下面被写入到控制台:

  1. 特里温菲尔德
  2. 李四
  3. 李四

我认为后者是行不通的,因为这将所需要的ovrride关键字。

所以问题是为什么我看到没有适当的关键字后面的名字?

我希望这是足够清晰的阅读。

问候,

+1

这是因为'writeName()'的子类是_hiding_基类的版本(你应该已经看到了编译器警告这个)。如果你把所有三个都投入到'员工'中,你应该看到第一个结果。 – JLRishe 2014-08-27 13:51:48

+0

@JLRishe非常感谢你的赞赏。 – 2014-08-27 18:41:13

回答

5

您所展示的代码中没有多态性。

将其更改为:

Employee employee = new Employee(); 
Employee partTimeEmployee = new PartTimeEmployee(); 
Employee fullTimeEmployee = new FullTimeEmployee(); 

,你会得到您预期的结果。

更新:

在OOP“多态性”(许多形式)的概念是指具有某种类型(基类或接口)的引用的代码的交易而有可能是不同类型的(后代,实现的实例)在这些参考之后。为了多态性“踢入”,必须有继承和虚拟方法(在接口实现中使用不同的术语,但让我们使用与您的代码示例相关的术语)。你有继承,但没有虚拟方法。对于常规(非虚拟)方法,方法调用将在编译时根据其方法被调用的对象的类型来解析。

下面的代码:

PartTimeEmployee partTimeEmployee = ...; 
partTimeEmployee.writeName(); 

很显然编译器调用什么方法writeName,它是PartTimeEmployee.writeName。 类似地,对于代码:

Employee partTimeEmployee = ...; 
partTimeEmployee.writeName(); 

的方法来调用是Employee.writeName

+0

我会将此标记为答案,考虑您提供的代码与您的答案。如果我可以问,帮助未来的“读者”。为什么你需要引用基类来为多态行为实例化一个子类?谢谢。 – 2014-08-27 18:52:49

+0

@TezWingfield - 查看更新。 – Igor 2014-08-27 21:35:20

+0

谢谢。一个伟大的信息更新去与您的答案。 – 2014-08-28 07:22:36

4

这被称为方法隐藏。你只是在派生类中隐藏基类方法。你应该得到一个警告,但它是完全合法的。欲了解更多信息,请参阅documentation。您可能还想看看this问题

+0

这不回答他的问题。他在询问关于方法实现的多态性,以及为什么当他不使用覆盖时调用基类方法的实现。 – Alan 2014-08-27 13:57:48

+0

@Alan方法隐藏确实解释了他所看到的行为。 – JLRishe 2014-08-27 13:59:01

+1

他的问题是为什么他没有使用覆盖而没有得到基类方法的实现。正确的答案是,因为他没有使用对基类类型的引用。他正试图测试使用虚拟方法的差异与否。通过使用基本类型的变量(他的错误),他无法证明,无论是否隐藏方法。 – Alan 2014-08-27 14:01:49

0

对于多态行为,其必须为override这些方法在PartTimeEmployeeFullTimeEmployee。你在那里做的是把这些方法隐藏在基类中。

 public class Employee 
     { 
      public Employee() 
      { 
       this.firstName = "Terry"; 
       this.lastName = "Wingfield"; 
      } 

      public string firstName { get; set; } 
      public string lastName { get; set; } 

      public virtual void writeName() 
      { 
       Console.WriteLine(this.firstName + " " + this.lastName); 
       Console.ReadLine(); 
      } 
     } 

    public class PartTimeEmployee : Employee 
    { 
     public override void writeName() 
     { 
      Console.WriteLine("John" + " " + "Doe"); 
      Console.ReadLine(); 
     } 
    } 
    public class FullTimeEmployee : Employee 
    { 
     public override void writeName() 
     { 
      Console.WriteLine("Jane" + " " + "Doe"); 
      Console.ReadLine(); 
     } 
    } 
+0

我看到您添加了Virtual/Override关键字,但在实例化子类时没有提及引用基类。感谢您的时间。 – 2014-08-27 18:46:57

0

使用C#,您可以使用“new”关键字重写基类的方法。如果你省略了这个关键字,编译器会编译你的源代码,就好像它存在一样。 所以现在的问题,我想,就是:什么是新的,覆盖之间的区别?这是一个很大的区别。

“新”指示编译器使用您的实现,而不是基类实现的,但不是直接引用类的任何代码将使用基类的实现。

“覆盖”用于虚拟和抽象方法。这指示编译器使用方法的最后定义的实现。如果方法在对基类的引用上调用,它将使用最后一个实现在该对象上覆盖它。

我希望我已经足够清晰。

+0

伟大的信息评论,但可能是主题的视域。我明白发生了什么以及应该输出什么内容,但代码中存在“错误”错误。还是一个很棒的评论!将有助于未来的“读者”。谢谢。 – 2014-08-27 18:50:14