2013-04-29 45 views
0

有人可以解釋這兩部分代碼之間的主要區別,以及爲什麼或何時應該使用對基類的引用,如對我來說,這是一回事。爲什麼要使用對基類的引用,我無法理解差異

internal class MyBaseClass 
{ 
    public string Field = "Hello"; 
    public void Print() 
    { 

     Console.WriteLine("This is the base class."); 
    } 
} 

internal class MyDerivedClass : MyBaseClass 
{ 
    public string FieldDerived = "Coucou"; 
    public new void Print() 
    { 

     Console.WriteLine("This is the derived class."); 
    } 
    public new void Print2() 
    { 

     Console.WriteLine("This is the derived class."); 
    } 
} 

internal class Program 
{ 
    private static void Main() 
    { 
     MyDerivedClass derived = new MyDerivedClass(); 
     MyBaseClass mybc = (MyBaseClass) derived; 
          // ↑ 
          // Cast to base clas 
    } 
} 

這是代碼,這爲我做的完全一樣的事情:

internal class MyBaseClass 
{ 
    public string Field = "Hello"; 
    public void Print() 
    { 

     Console.WriteLine("This is the base class."); 
    } 
} 

internal class MyDerivedClass : MyBaseClass 
{ 
    public string FieldDerived = "Coucou"; 
    public new void Print() 
    { 

     Console.WriteLine("This is the derived class."); 
    } 
    public new void Print2() 
    { 

     Console.WriteLine("This is the derived class."); 
    } 
} 

internal class Program 
{ 
    private static void Main() 
    { 
     MyDerivedClass derived = new MyDerivedClass(); 
     MyBaseClass mybc = new MyBaseClass(); 
           // ↑ 
           // Use the base class 
    } 
} 
+0

什麼是什麼? – Jodrell 2013-04-29 13:43:38

+0

我可以訪問完全相同的方法/領域,與派生和mybc,我真的不明白什麼是參考點。 – Meds 2013-04-29 13:45:31

+0

看起來像下面的調用 - MyBaseClass mybc = new MyBaseClass(); vs.(MyBaseClass)派生;' – wjhguitarman 2013-04-29 13:45:59

回答

4

用法之間有兩點區別。

在第一個示例中,轉換是不必要的,並且mybc和派生兩個都指向相同的對象,這是派生類的一個實例。您始終可以將派生類視爲它們是基類的實例(因爲它們是),不需要投射。

在第二個示例中,它們是完全獨立的對象實例,引用的對象實際上也是單獨的類型。

1

在第一個例子演員是多餘的,因爲它總是合法的對待一個派生類,如果它是基礎班。

如果您想要覆蓋Print方法(可能是您在此方案中想要的),請在基類中將其標記爲virtual,並在派生類中將其標記爲override。然後你會在基類和派生類之間得到不同的行爲。

2

不同之處在於,您只在第一個示例中創建一個對象,而在第二個示例中僅創建兩個對象。

  1. 創建對象並轉換爲其基類的對象。剝離MyDerivedClass添加的所有功能。鑄造前完成的所有更改將保留。
  2. 創建MyDerivedClass的對象和MyBaseClass的對象,它們之間沒有任何關係。

public void TestThisStuff() 
     { 
      // 1 example 
      MyDerivedClass derivedObj = new MyDerivedClass(); 
      derivedObj.Field = "Changed field"; 
      derivedObj.FieldDerived = "Changed derived field"; 
      MyBaseClass baseObj = (MyBaseClass)derivedObj; 
      // baseObj.Field value will be "Changed field" 
      // baseObj.FieldDerived will not be accessible because it is not presend in the base class

// 2 example MyDerivedClass derivedObj2 = new MyDerivedClass(); derivedObj2.Field = "Changed field"; derivedObj2.FieldDerived = "Changed derived field"; MyBaseClass baseObj2 = new MyBaseClass(); // baseObj2.Field value will be "Hello" // baseObj2.FieldDerived will not be accessible because it is not presend in the base class baseObj2.Field = "Change my field because it's not related to anything else." // derivedObj2.Field value will be "Changed field" // derivedObj2.FieldDerived will not be accessible because it is not presend in the base class }
1

我不知道你想在「使用基類」做什麼。

通常,如果您有一個派生類的引用,則不需要將其轉換爲其基類。通常,當您使用派生類的抽象時,使用基類和派生類。也許你知道這一點,所以我並不意味着任何不敬。例如,你的基類可以是Animal,你的派生類是Dog和Cat。基類中的抽象可能是Eat。所以如果你有一個動物列表,你可以通過調用抽象方法Eat來餵它們,而不必知道每個動物是什麼類型的動物,也不必將每個動物投射到它的派生類。

對不起,如果不是你問。

2

派生類用於實現is-a關係。想象一下,一個類:

internal class MySpottedDogClass : MyDogClass : MyAnimalClass 

因爲斑點狗是狗,和狗是動物

如果我創建一個新的斑點狗

MySpottedDogClass rover = new MySpottedDogClass(); 

然後我可以叫

rover.countSpots() 

僅適用於斑點狗的動作。方法是SpottedDog類

rover.bark() 

這適用於所有的狗的一部分,所以它在狗類

rover.weight() 

這適用於所有的動物實現的,因此它在動物類中實現。子類是創建更一般的東西的一種方式。我認爲你需要閱讀一下面向對象的設計

也許這有助於按照這些術語思考你的設計。

你的第一個例子是像

SpottedDogClass rover = new SpottedDogClass(); 
DogClass dogReferenceToRover = (DogClass) rover; 

它們都指向同一個對象。 dogReferenceToRover.bark()可以。 dogReferenceToRover.countSpots()是無效的,因爲你不能對狗進行這樣的操作(只有一隻發現的狗),並且引用有類型,而不是對象。

你的第二個例子是這樣的

SpottedDogClass rover = new SpottedDogClass(); 
DogClass fido = new DogClass(); 

你做出了斑點狗和狗這一次。有2個對象。

+0

我喜歡它,謝謝。 – Meds 2013-04-29 14:27:57

0

也許你的問題需要關於c#中類的多態行爲?

1

如果你認爲一個人爲的例子,

abstract class Cake 
{ 
    public virtual bool Edible { get { return true; } } 
} 

class PooCake : Cake 
{ 
    public new bool Edible { get { return false; } } 
} 

class TurdCake : Cake 
{ 
    public override bool Edible { get { return false; } } 
} 

和下面的代碼片段

var turd = new TurdCake(); 
var poo = new PooCake(); 
Console.WriteLine(
    "PooCake is{0} edible", 
    poo.Edible ? string.Empty : " not"); 
Console.WriteLine(
    "PooCake is{0} edible", 
    (Cake)poo.Edible ? string.Empty : " not"); 
Console.WriteLine(
    "TurdCake is{0} edible", 
    turd.Edible ? string.Empty : " not"); 
Console.WriteLine(
    "TurdCake is{0} edible", 
    (Cake)turd.Edible ? string.Empty : " not"); 
Console.ReadKey(); 

你會意識到你應該,因爲它打破了繼承模型的非常仔細地使用new關鍵字。在這種情況下,它可能會讓你吃基地的便便蛋糕。

如果您調試並瀏覽代碼,您會看到,在TurdCake的情況下,該屬性被正確覆蓋,並且基礎實現不可訪問。在PooCake示例中,該屬性僅被隱藏,對基本類型的引用顯示了基本實現。這可能會導致不滿意的結果。

0

由於許多不同的原因,有時派生類會隱藏基類中定義的方法或屬性。

考慮這個例子:

public class BaseClass 
{ 
    public string GetSomeValue() { return "base class"; } 
} 

在派生類中,這可能是由一個新的方法「重新佈線」:

public class DerivedClass : BaseClass 
{ 
    // hides the base method (basically you're hijacking the signature) 
    public new string GetSomeValue() { return "derived class"; } 
} 

需要注意的是,你幾乎可以new基礎上的任何簽名類。這是劫持簽名的一種非常強大的方式,應謹慎使用。

多態地,當調用GetSomeValue時,DerivedClass的實例將始終返回"derived class"

雖然有時候,調用基類方法而不是派生類方法可能非常關鍵。在這種情況下,它將使意義上溯造型的派生的實例是這樣的:

var result = ((BaseClass)derivedInstance).GetSomeValue(); // returns "base class" 

當你向上轉型((BaseClass)derivedInstance),你可以使派生類忽略了它自己的new方法和調用基類的方法來代替。這在某些情況下可能是有意義的,但除非你正在做一些組件設計或其他多態的大量代碼提升,否則我不認爲你會在日常的基礎上看到這一點。那麼,至少,沒有(盾眼)。

相關問題