2013-07-08 41 views
1
class Parent 
{ 
    public void foo() 
    { 
     Console.WriteLine("Hello from the foo inside Parent"); 
    } 

    public virtual void bar() 
    { 
     Console.WriteLine("Hello from the bar inside Parent."); 
    } 

    public void foobar() 
    { 
     Console.WriteLine("Hello from the foobar inside Parent."); 
    } 
} 
class Child : Parent 
{ 
    public void foo() 
    { 
     base.foo(); 
     Console.WriteLine("Hello from the foo inside Child"); 
    }   

    public override void bar() 
    { 
     base.bar(); 
     Console.WriteLine("Hello from the bar inside Child."); 
    } 

    public new void foobar() 
    { 
     base.foobar(); 
     Console.WriteLine("Hello from the foobar inside Child.");    
    } 
} 

上面就是我使用來測試我在C#中繼承knowlege的代碼,但我這裏有一個困惑:孩子裏面C#繼承和壓倒一切的

  1. 功能foo()隱藏的foo()家長。
  2. 功能bar()裏面的孩子隱藏父母的bar()
  3. 功能foobar()孩子隱藏在裏面的父母的bar()()

所有三個功能使用不同的技術來隱藏父功能。任何人都可以請引導我,這三個之間有什麼不同,以及哪一個使用什麼時候?

回答

2

首先,1和3是一樣的,編譯器/ IDE(Visual Studio中)會自動將您的意思做3號,如果你1號。你會發現,它把一個綠線的名義下foo()並告訴您使用new關鍵字。因此,在現實中,只有兩種類型的基於繼承的方法改變的:

  1. 方法覆蓋
  2. 方法隱藏

方法覆蓋是當一個類聲明其方法是虛擬的,基本上說'任何繼承我的類都可以自由地覆蓋這個'。這意味着無論如何,如果子類覆蓋該方法,則會調用被覆蓋的版本。

另一方面,隱藏方法是孩子反叛,並說'只要我作爲一個孩子班級存在,我將忽略我的父母實施,而不是這樣做'。這裏的訣竅是,當孩子類被視爲父類時,父類的實現被調用。

下面是一個例子,假設正在使用類設置:

Child c = new Child(); 
c.foo(); 
c.bar(); 
Parent p = c; 
p.foo(); 
p.bar(); 

注意,Child c可以存儲在父變量,因爲它繼承。 從父類繼承的任何子類都可以被視爲其父類的一個實例。

現在嘗試加入這個類混進去:

class MaleChild : Parent 
{ 
    public new void foo() 
    { 
     base.foo(); 
     Console.WriteLine("Hello from the foo inside MaleChild"); 
    } 

    public override void bar() 
    { 
     base.bar(); 
     Console.WriteLine("Hello from the bar inside MaleChild."); 
    } 
} 

和運行類似的測試:

Parent[] p = new Parent[2]; 

p[0] = new Child(); 
p[1] = new MaleChild(); 

p[0].foo(); 
p[0].bar(); 
p[1].foo(); 
p[1].bar(); 

現在你看,即使兩個繼承的類都被視爲他們的父母,重寫的方法對於繼承的類是唯一的。這允許父類爲它的工作方式定義一個基本的大綱,而子類對此進行細化並更具體地做事。然而,因爲子類可以完成父母的所有事情,所以可以將其視爲父母。

這個概念被稱爲多態。

1

首先,在第一和第三個是相同的,唯一的區別是第三個不會給編譯時警告

Child.foo()」隱藏繼承的成員`Parent.foo( )」。如果隱藏的目的

繼承的真正價值顯示出來,當你有基本類型的變量,不知道該變量指向實例的類型使用新的 關鍵字。

請檢查前三個調用的輸出以及它們與最近三次調用的不同。

Parent p = new Child(); 
Child c = new Child(); 

p.foo(); 
p.bar(); 
p.foobar(); 
Console.WriteLine("------------------------"); 
c.foo(); 
c.bar(); 
c.foobar(); 
2

要看到差別嘗試下面的代碼:

Console.WriteLine("Parent->Parent"); 
Parent p = new Parent(); 
p.foo(); 
p.bar(); 
p.foobar(); 

在這種情況下,你有Parent型指向Parent類的實例變量。這裏沒有任何東西被隱藏或覆蓋。父類的方法被調用。現在創建Child類型,它指向的Child實例變量:

Console.WriteLine("Child->Child"); 
Child c = new Child(); 
c.foo(); 
c.bar(); 
c.foobar(); 

在這種情況下,子類的所有方法被調用。也沒什麼有趣的。現在創建Parent類型,它指向的Child實例變量:

Console.WriteLine("Parent->Child"); 
Parent p = new Child(); 
p.foo(); // you have warning and parent method is invoked 
p.bar(); // child overridden method invoked 
p.foobar(); // no warning, parent method is invoked 

在這種情況下,你可以看到多態性行動 - 方法,這些方法在子類中重寫被調用。如果方法未被覆蓋,則調用父方法。但是,你也有一個警告消息:

警告1 'Namespace.Child.foo()' 隱藏繼承成員 'Namespace.Parent.foo()'。如果需要隱藏,請使用新關鍵字。

它說的是,你在子類中的方法用相同的簽名方法父類,其中隱藏父類的實現已宣佈。從最後一個樣本可以看出,隱藏與重寫不同。當你有父類型的變量時,那麼在子中重寫的成員將被調用。但隱藏的方法在最後一種情況下不會被調用。

通常你不需要這樣的行爲(即隱藏一些成員),這就是爲什麼編譯器會警告你。但如果由於某種原因您需要此行爲(例如您沒有自己的父級代碼,並且無法使父級方法虛擬爲),那麼您應該使用new關鍵字來抑制此警告並顯示您明白自己在做什麼。這就是爲什麼你沒有看到foobar方法的警告。

+0

請你解釋一下,在你的第二個代碼示例中,爲什麼/如何重寫被調用的方法,而我們甚至沒有實例化孩子?由於我對多態不熟悉,所以請不要介意我的問題對你來說是否愚蠢! –

+1

@KamranAhmed我改變了樣品的順序,最後顯示最有趣的情況。所以,我想你是在問最後一個案子。實際上你在這兒實例化了一個小孩 - 'new Child()'是實例化的。但是您將對此實例的引用分配給基本類型的變量。 –