2015-11-26 41 views
3

我在C#以下類:虛擬和新的C#

public class BaseClass 
{ 
    public virtual void DoSomethingVirtual() 
    { 
     Console.WriteLine("Base.DoSomethingVirtual"); 
    } 

    public new void DoSomethingNonVirtual() 
    { 
     Console.WriteLine("Base.DoSomethingNonVirtual"); 
    } 
} 

public class DerivedClass : BaseClass 
{ 
    public override void DoSomethingVirtual() 
    { 
     Console.WriteLine("Derived.DoSomethingVirtual"); 
    } 

    public new void DoSomethingNonVirtual() 
    { 
     Console.WriteLine("Derived.DoSomethingNonVirtual"); 
    } 
} 

class ConsoleInheritanceTrial 
{ 
    static void Main(string[] args) 
    { 
     Console.WriteLine("Derived via Base Reference."); 

     BaseClass BaseRef = new DerivedClass(); 
     BaseRef.DoSomethingVirtual(); 
     BaseRef.DoSomethingNonVirtual(); 

     Console.WriteLine(); 
     Console.WriteLine("Derived via Dereived Reference."); 

     DerivedClass DerivedRef = new DerivedClass(); 
     DerivedRef.DoSomethingVirtual(); 
     DerivedRef.DoSomethingNonVirtual(); 

     Console.Read(); 
    } 
} 

運行的主要功能後,我得到這個:

Derived Via Base Reference 
Derived.DoSomethingVirtual 
Base.DoSomethingNonVirtual 

Derived Via Derived Reference 
Derived.DoSomethingVirtual 
Derived.DoSomethingNonVirtual 

爲什麼baseRef.DoSoemthingNonVirtual調用基函數?它是否與該函數的派生類中的「new」關鍵字有關? 我明白「虛擬」和「覆蓋」的重要性。我的混淆是由聲明造成的: BaseClass BaseRef = new DerivedClass();

+0

這裏'new'的唯一影響是抑制警告。 –

回答

4

爲什麼BaseRef.DoSoemthingNonVirtual調用基函數?

這是你的宣言:

BaseClass BaseRef = new DerivedClass(); 

在這裏,您創建DerivedClass類型的對象,並分配給一個變量,BaseClass類型的對它的引用。可以這樣做,因爲DerivedClass的基類型爲BaseClass

然後在這裏

BaseRef.DoSomethingNonVirtual 

調用方法DoSomethingNonVirtual

BaseRef是什麼類型的?

它是BaseClass。所以這個類的方法被調用,而不是DerivedClass的方法。

所以這裏的問題是,你已經創建了一個類型爲DerivedClass的對象,並且你將該對象的引用賦值給一個BaseClass類型的變量。 所以CLR,當看到這個調用首次

BaseRef.DoSomethingNonVirtual 

必須解決的BaseRef類型,然後看對象的方法表,挑相應的IL並在最後產生相應的本地代碼。 CLR如何解決這個問題?作爲BaseClass類型的對象而不是DerivedClass

2

如果您在派生類中定義了virtual方法而您override它將在所有級別中覆蓋該行爲。基類將使用派生方法。這就是爲什麼覆蓋的方法大多數情況下會在內部調用其基本實現的原因。

隨着new您定義的方法具有相同的名字 - 沒有更多...

基類不知道這個方法,所以它不會被調用。

3

爲什麼baseRef.DoSomethingNonVirtual調用基函數?

由於baseRef編譯時類型是BaseClass,該方法調用被解析爲BaseClass.DoSomethingNonVirtual()baseRef引用的對象的實際類型是DerivedClass,但編譯器不知道它。

此方法不是虛擬的,所以當它在運行時被調用時,CLR將簡單地調用BaseClass實現。