[英]C# creating an instance of a class and derived class
我在c#程序中嘗試了以下代碼。 這僅是為了學習OOP概念。
class a
{
public void testa()
{
}
}
class b:a
{
public void testb()
{
}
}
a a1 = new b();
b b1 = new a();
關於上述代碼,我有以下查詢。
a a1=new b()
; b
構造函數分配給a1
也無法訪問a1.testb()
? a a1=new a()
和a a1=new b()
什么區別? 1)如果您的意思是這一行:
b b = new a();
這是因為每個b
都是a
但並非每個a
都是b
2-3) a a1=new b();
是什么意思a a1=new b();
為什么即使將b
構造函數分配給a1
也無法訪問a1.testb()
?
這意味着用戶可創建的對象b
類,但得到引用它作為a
(你可以把它低谷而無需進行轉換只能作為參考這樣a
甚至是b
)
我將您的類和方法名稱更改為現實世界中的等效名稱,以便更好地理解。 我將a
命名為Animal
,將testa
命名為Eat
,將b
testb
為Human
,將testb
為Talk
。 因此,我們有:
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
行為。
對您來說, 繼承和多態概念可能還不清楚。 本文可能會為您提供幫助。
如果類b
從繼承a
,你可以把它想象成一條“專業化”的a
。 所以,你可以很容易地明白, b
,可以使用/視為a
實例,但相反的是不是真的!
為什么我在第二行出現錯誤?
因為b b1 = new a();
不是有效的分配。 如前所述,您可以將繼承的類實例分配給基類變量,但不能相反!
a1 = new b()是什么意思;
這種分配是正確的,因為您可以肯定地使用更具體的類實例作為基類實例。
為什么即使將b的構造函數分配給a1,也無法訪問a1.testb()?
當您從一個類繼承時,該類的所有public
方法和protected
方法都將被繼承,並且您可以在新類中訪問或重寫該方法。 但是testb()
不是繼承的方法。 是在類b
內定義的新方法,因此只有b b1=new b();
以下分配時才可以使用它: b b1=new b();
如果定義a1 = new b(),要使用b中聲明的方法,可以將a1強制轉換為b
a a1 = new b();
((b)a1).testb();
將您的課程視為合同,以保證某些操作的存在。 類a
定義了一個操作,類b
繼承所有操作a
,定義了自己的另一個。
第一行:
a a1 = new b();
聲明一個名為的變量a1
型的a
,這意味着你把這個變量應該有所有的操作類型的任何值a
要求。 new b()
創建類b
的新實例,並將其分配給變量a1
。 由於類b
繼承了類型a
所有操作,因此可以將類型b
的值分配給類型a
的變量。
在第二行:
b b = new a();
同樣,您定義一個變量,該變量應具有類型b
定義的所有操作。 但是由於您輸入的類型a
的值testb
類型b
所需的testb
操作,因此編譯器不會接受此值。
關於第三個問題,編譯器僅知道變量( a
)的類型,而不知道您實際為其分配的值。 您基本上告訴編譯器“我保證這個值將定義testa
操作。現在讓它執行testb
操作!” 編譯器不知道變量的實際值,因此就其而言,這是不可能的。
至於a a1=new a()
和a a1=new b()
之間的區別:在兩種情況下,都會創建類型a
a的變量。 在第一個表達式中,分配給該變量的值是類型a
的新創建實例,而在第二個表達式中,值是類型b
的新創建實例。 由於“B”型基本型的擴展版本a
,編譯器知道這一切,你可以問類型的實例的a
也可以通過類型的實例滿足b
,所以它只是把值,好像它是鍵入a
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.