2014-08-27 111 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