2015-07-05 58 views
4

我在練習的繼承,在C#中使用一個測試程序,我發現了下面的語句不會引發錯誤:一個爲什麼會創建一個基類對象參照派生類

BaseClass baseObj = new DerivedClass(); 

爲什麼這種說法是否允許,並且在這種情況下,這種說法對程序員是否有用?

這裏是我的測試程序:

class BaseClass 
{ 
    public void show() 
    { 
     Console.WriteLine("Base Class!"); 

    } 
} 

class DerivedClass : BaseClass 
{ 
    public void Display() 
    { 
     Console.WriteLine("Derived Class!");    
    } 
} 

class Result 
{ 
    public static void Main() 
    {    
     BaseClass baseObj = new DerivedClass(); 
     baseObj.show(); 
    } 
} 
+3

「爲什麼允許此語句」 - 因爲派生類的實例可以被視爲基類的一個實例。這是C#中多態性的基礎。 –

+0

因此,它們僅在與虛擬方法(基類中)和覆蓋(派生類)中配對時纔有用? – user3083590

+1

不是。只要你想表明所有的代碼只能使用基類成員操作,它們就很有用,所以選擇使用哪個派生類本地化到你實例化它的單個地方。 –

回答

10

我建議你更詳細地閱讀繼承和多態性。 (herehere

在這個答案我試圖保持足夠簡單的概念。

Why is this statement allowed and is there a situation where this statement would be useful to a programmer?

但是爲了解釋你的問題有點讓我們來看看面向對象的程序需要使用多態性的簡單而經典的例子。

假設您正在編寫一個程序,需要存儲一些形狀並將其顯示在屏幕上。爲了達到這個目的,你需要在數組中存儲所有的形狀。對?

假設我們的類的類似:

class BaseShape 
{ 
    public virtual void Display() 
    { 
     Console.WriteLine("Displaying Base Class!"); 

    } 
} 

class Circle : BaseShape 
{ 
    public override void Display() 
    { 
     Console.WriteLine("Displaying Circle Class!");    
    } 
} 

class Rectangle : BaseShape 
{ 
    public override void Display() 
    { 
     Console.WriteLine("Displaying Rectangle Class!");    
    } 
} 

而且你的陣列可以object陣列。像這樣:

object[] shapes = new object[10]; 

在你的應用程序中,你需要編寫一個方法來顯示形狀。

一種解決方案可以迭代所有形狀並調用正確的形狀類型的方法。像這樣:

public static void DisplayShapes_BAD(){ 

    foreach(var item in Shapes) 
    { 
     if(typeof(Circle) == item.GetType()) 
     { 
      ((Circle)item).Display(); 
     } 
     if(typeof(Rectangle) == item.GetType()) 
     { 
      ((Circle)item).Display(); 
     } 
    } 
} 

但是當另一種類型的Shape出現在應用程序中時會發生什麼?基本上你需要修改DisplayShapes_BAD()方法來支持新類型的Shape(在方法體中增加新的if語句)

這樣你就打破了面向對象編程的Open/Closed principle。而且你的代碼不太可維護。

更好的方法來存儲形狀,以避免這種不好的方法是使用BaseShape數組。像這樣:

public static List<BaseShape> Shapes = new List<BaseShape>(); 

這裏是如何項添加到形狀,這個名單:

Shapes.Add(new Circle()); 
Shapes.Add(new Rectangle()); 

現在來看看良好的執行DisplayShapes方法。

public static void DisplayShapes_GOOD() 
{ 
    foreach(var item in Shapes) 
    { 
     item.Display(); 
    } 
} 

在上述方法中,我們呼籲項目類型的BaseShapeDisplay方法。但是C#知道如何調用正確的方法(例如圓形顯示或矩形顯示)。這種機制是多態性的。

完整代碼共享爲Gist

+1

謝謝。我現在認爲我已經理解了應用程序 – user3083590

+0

非常好的解釋! –

1

按我在Java的理解,你正在嘗試使用BaseClass的參考varibale baseobj調用DerivedClass的對象,這種編碼方案是完全有效的,因爲它是提供運行時多態性的功能。

在運行時多態性讓我們瞭解上傳。當父類的參考變量用來指子類則的對象時,它被稱爲上溯造型

class A{} 

class B extends A{} 

A obj= new B // Upcasting. 

運行時多態性是在其中被覆蓋的方法的調用是在運行時解析而一個過程比編譯時。

既然你不重寫顯示在派生類中方法,你是不是在做運行時多態性,但簡單地向上轉型,當我們想在runntime解決調用來重寫方法上溯造型是非常有用的。

2

首先,問題爲什麼允許,只是因爲派生類的一個實例是基類(子類型多態)的一個實例。同樣可以將任何派生類分配給對象變量:所有.net類最終都從對象派生,因此您也可以完成object baseObj = new DerivedClass()

用於聲明的類型的目標是指示哪種類型的接口正在處理(意圖)。如果你將變量聲明爲對象,你會說只有引用是重要的。如果聲明爲BaseClass,則表示您使用的是BaseClass的屬性和方法非常重要的對象。通過使用BaseClass baseObj = new DerivedClass(),你說你需要BaseClass功能,但是使用DerivedClass實例來定義BaseClass中描述的映射的工作。

這樣做的一個原因可能是BaseClass是抽象的(BaseClass通常是),你想要一個BaseClass並需要一個派生類型來啓動一個實例,並且選擇哪一個派生類型應該對實現類型有意義。

更經常使用它的一個原因是因爲在任何時候,從BaseClass派生的另一個類都可以分配給同一個變量。考慮:

BaseClass baseObj = SomeCriterium ? (BaseClass)new DerivedClass() : new AlternateDerivedClass(); 

的例子中的變量的範圍僅在主要方法,但如果它在類人的任何地方,或者它可以被通過屬性或以其它方式改變,通過使用BaseClass的,任何人使用您的類可以分配其他BaseClass(派生)實例,而不是隻派生DerivedClass(派生)實例。

最後,對於重新分配,使用接口聲明(據多態性而言,同樣可以因爲它可以被應用到聲明一個實現接口,而不是類的一個基類)的例子:

IEnumerable<T> values = new List<T>(); 
if(needfilter) 
    values = values.Where(el => filtercriterium); 

如果值被聲明爲List,則值變量不能重新用於篩選的枚舉。基本上首先你說你只需要枚舉值變量。之後,您可以使用其他枚舉重新分配值,而不是僅使用列表。

相關問題