2013-11-05 45 views
1

我在我的c#程序中嘗試了下面的代碼。這僅僅是爲了學習OOP概念。C#創建類和派生類的實例

class a 
    {  
     public void testa() 
     { 
     } 
    } 
    class b:a 
    {  
     public void testb() 
     { 
     } 
    } 

    a a1 = new b(); 

    b b1 = new a(); 

我有關於上述代碼的以下查詢。

  1. 爲什麼我在第二行出現錯誤?
  2. 什麼意思是a a1=new b();
  3. 爲什麼a1.testb()不可訪問,即使b的構造函數被分配給a1
  4. a a1=new a()a a1=new b()有什麼不同?
+0

可以通過此鏈接幫助您。 http://msdn.microsoft.com/en-us/library/vstudio/dd460654.aspx –

+0

您需要了解繼承的概念。 b類實際上是a類的更加明確和詳細的形式。因此,它具有a級所提供的所有功能,但更多。這就是你可以從b引用b的構造函數的原因。現在您需要了解a1.testb()是類b提供的額外功能,哪個類a不具備。所以,a1不能調用testb()。 –

+0

@WasiqAli我會同意你,如果我寫了1 =新的a()而不是a1 = new b()。在那種情況下,我不能訪問b的方法。但是,既然我將b的構造函數賦值給了爲什麼它不可訪問? –

回答

3

1)如果你的意思是這條線:

b b = new a(); 

這是因爲每個ba但不是每一個ab

2-3)什麼是a a1=new b(); 爲什麼a1.testb()意思即使b的構造函數被分配給a1也不可訪問?

這意味着你創建b類的對象,但得到引用它作爲a(你可以把它低谷此參考不鑄件只a甚至是b

+0

你能解釋一下,「你可以通過這個參考來對待它,而不是僅僅把它當作b來處理」。 –

+1

對於編譯器'a1'只是'a',它可以讓你只訪問'a'類中定義的fields/properties/methods,但你知道它實際上是'b',你可以寫這樣的東西(它被稱爲[cast](http://msdn.microsoft.com/en-us/library/ms173105(v = vs.110).aspx)):'b a2 =(b)a1'和編譯器將能夠通過'a2'調用'b'的所有方法。 Casting在運行時執行,所以如果'a1'不是'b',它會給你一個運行時錯誤。 –

+0

[C#大部分是靜態類型語言,因爲編譯器會確定有關每個表達式類型的事實。 C#大多數情況下是一種類型安全的語言,因爲它可以防止一種靜態類型的值存儲在不兼容類型的變量中(以及其他類似的類型錯誤)。](http://blogs.msdn.com/b/ericlippert /archive/2012/10/15/is-ca-strongly-typed-or-a-weakly-typed-language.aspx) –

1

如果你定義的A1 =新型B (),使用b中聲明的方法,你可以爲b

a a1 = new b(); 
((b)a1).testb(); 
+0

所以即使分配的構造函數bi將無法訪問b的方法使用a1?那麼創建一個類的實例是什麼意思? –

+0

在運行時將創建變量實例,在編譯器將a1視爲a的類型之前,除了使用所有方法和其他類型聲明的類型爲 – DeveloperX

+0

@ user833985之外,還可以有多個從「a」派生的類,但希望將它們存儲在一個地方(列表或數組),以便爲基類創建存儲並將所有內容放在那裏。後來如果你想使用派生類的功能,你可以像下面這樣引用:'b bInst =(b)aInstance;'。並且您可以獲得[基本類的引用的虛擬方法](http://msdn.microsoft.com/zh-cn/library/aa645767(v = vs.71).aspx),但實際上具有一個的派生。 –

0

認爲沒定義爲一個合同,保證某些操作的存在。 類a定義了一個操作,類b繼承了a的所有操作並定義了它自己的另一個操作。

第一行:

a a1 = new b(); 

聲明瞭一個名爲aa1變量,這意味着你給這個變量應該有任何值的所有操作類型a要求。 new b()創建了一個b類的新實例,該實例被分配給變量a1。由於類b繼承了類型爲a的所有操作,因此可將b類型的值分配給類型爲a的變量。

在第二行:

b b = new a(); 

類似地,可以定義應當具有由b類型定義的所有操作的變量。但是,由於您輸入的值類型爲a,它沒有定義testb操作類型b要求,編譯器不接受此。

至於你的第三個問題,編譯器只知道你的變量的類型(a),而不是你實際分配給它的值。你基本上告訴編譯器「我保證這個值將定義testa操作,現在讓它執行操作testb!」編譯器不知道變量的實際值,所以就它而言,這是不可能的。

至於a a1=new a()a a1=new b()之間的差: 在兩種情況下,將創建a類型的變量。在第一個表達式中,分配給此變量的值是a類型的新創建實例,而第二個值是b類型的新創建實例。由於類型'b'基本上是a類型的擴展版本,因此編譯器知道您可能需要的類型爲a的實例的所有內容都可以通過類型爲b的實例來滿足,因此它只是將值看作是鍵入a

+0

感謝您提供詳細的解釋。你能告訴我a1 = new b()的左邊部分和右邊部分是什麼嗎?它是否創建了一個b的實例並分配了b()或類似的構造函數? –

+0

@ user833985不,它創建一個'b'的實例並將其賦值給變量'a'。我已經擴展了我對上述問題的描述。 – Rik

2

我將您的類和方法名稱更改爲現實世界的等價物以更好地理解。我叫aAnimaltestaEat,bHumantestbTalk。所以我們有:

class Animal {  
    public void Eat() { } 
} 

class Human : Animal {  
    public void Talk() { } 
} 

Animal a1 = new Human(); 

Human b1 = new Animal(); 

好的,回到您的問題。

1)你會在第二行發生錯誤,因爲每個動物都不是人類。是嗎?

2)a1=new b()根據我們新的命名約定,轉向a1 = new Human這意味着Animal a1 = new Human。所以,這是正確的,因爲人類是一種動物。

3)a1.testb()根據我們新的命名約定,轉向a1.Talk()。那麼,a1是一種動物(Animal a1),我們不能指望動物說話。

更多:

想想class是一組屬性和行爲。例如,我們有一個名爲Animal的組定義了一個Eat行爲。另一個名爲Human的組延伸Animal組,並且它也有自己的行爲,名稱爲Talk。正如我們所知,Human也有其超羣的行爲 - 例如在本例中爲Eat

當我們有一組Animal的實例時,我們可以期待它吃東西。但我們不能要求它說話。這是不可能的。另一方面,我們從組Human中選擇的每個項目實際上都是Animal。所以我們可以讓他吃。

當我們有一個Human實例時,我們可以要求他的行爲爲Human,也可以是Animal。我的意思是,我們可以讓他去Talk,我們也可以讓他去Eat。每個Human可以位於人類組和動物組。

1)當我們說Human b1 = new Animal();它說正是:從Animal組接了一個項目 - 右邊部分 - 並把它放在Human組 - 左邊 - 這是不可能的。因爲有很多不是人類的動物。

2)當我們說Animal a1 = new Human:從Human組挑選一個項目 - 右部分 - 並將其放入Animal組 - 左部分 - 這很容易實現。

3)當我們說a1.Talk()時,我們預計Animal會說話。我的意思是我們預計Animal行動Human行爲是不可能的。

+0

所以如果即時通訊創建人類b1 = new Animal()的實例;和a1.Talk()不可訪問,那麼Human b1 = new Animal()之間有什麼區別?和動物b1 =新動物(); –

+0

你不能通過實例化一個Animal來創建一個'Human'。請仔細閱讀答案。 「動物」不是「人」。斑馬,狗,貓,它們是動物,但不是人類。 –

+0

我明白根據你的概念解釋,它是不可能的。但理論上我無法說服自己有什麼不同b/w人類b1 =新的動物();和動物b1 =新動物(); –

2

可能繼承多態性概念對你來說還不是很清楚。 This article可能會幫助你。

如果b類繼承自a,則可以將其想象爲a的「專業化」。 所以你可以很容易地明白,b可以被用作/看作是一個a的實例,但反過來卻不是這樣!


爲什麼即時得到在第2行錯誤?

因爲b b1 = new a();不是有效的賦值。如上所述,您可以將繼承的類實例分配給基類變量,但不是相反!

a1 = new b()是什麼意思;

此賦值是正確的,因爲您肯定可以使用更具體的類實例作爲基類實例。

爲什麼即使b的構造函數被賦值給a1,a1.testb()也不可訪問?

當你從一個類繼承,這一切階級的publicprotected方法是繼承的,你可以在新類來訪問或重寫。但testb()不是繼承的方法。是b類中定義的新方法,因此只有在完成此作業時纔可以使用它:b b1=new b();

+0

但是,在這裏我創建了類b的構造函數並將其分配給行a a1 = new b()中的實例a1;那麼爲什麼b的方法不能被a1訪問?那麼你的意思是說a1 = new a()和a1 = new b()是否相同? –

+0

在類「b」中實現的方法只能在類「b」的實例中調用**。即使你實例化一個新的b(),你也將它分配給一個「a」變量,所以只有類「a」中定義的方法纔可用。 – davioooh

+0

so a1 = new a()和a1 = new b()是否相同? –