原創 關於繼承例項化的說明 c

2021-04-13 08:02:52 字數 3594 閱讀 3233

對於繼承例項化的四種情況實際開發中遇到的挺多的,其中父類宣告子類實現的情況,比如說father f=new sun();這種情況得到的到底是父類的例項還是子類的例項呢.

先看下面這個例子:

三個類,乙個父類,乙個子類,乙個包含main()函式的測試類;

1.父類:

using system;

namespace testinherit

public string returnbbb()}}

2.子類

using system;

namespace testinherit

public string returnbbb()}}

3.測試類

using system;

namespace testinherit}}

首先作個說明,上面的類編譯的時候不會報錯,但是會出乙個警告:「testinherit.sun.returnbbb()」上要求關鍵字 new,因為它隱藏了繼承成員「testinherit.father.returnbbb()」,因為兩個類裡面有兩個同名的方法,和returnstringaaa()方法是完全不一樣的,returnstringaaa()方法是子類重寫(override)父類中的虛方法.加上new 關鍵字後編譯完全通過,其結果和不加new得情況一樣的,不加new其實也隱藏了父類中的同名方法.

其中第二種,第三種情況比較簡單:

sun sun2=new sun ();得到的是子類的例項,結果當然是

"sun_aaa";

"sun_bbb";

father father2=new father ();得到的是父類的例項,結果為

"father_aaa";

"father_bbb";

對於第一種情況,

father father1=new sun ();,得到的結果什麼呢?

結果是這樣的:

"sun_aaa";

"father_bbb";

其中"sun_aaa"比較清楚,但是"father_bbb"是為什麼呢?開始我認為是father1是father的例項,父類中的方法和屬性對其可見,所以結果是"father_bbb";

如果上面的例子是這樣呢?

((sun)father1).returnbbb();那得到的結果又是什麼呢?

結果是"sun_bbb",這樣看來其實"父類宣告,子類實現"得到的是子的例項;如果照開始的想法,是父的例項的話,其實在上面強制型別轉化的時候可能就會像最後一種情況一樣,出"指定的轉換無效"的異常了.所以像我們平時經常會用到的ilist list=new arraylist();毫無疑問就是arraylist的例項,再說ilist也是不能被直接例項化的.在上面的例子中,那樣例項化的時候,其實父遮蔽了子類中的returnbbb()方法,而強制型別轉化為sun以後,sun裡面的returnbbb()又隱藏了父類中的同名的方法,所以出現了上面的結果.

有乙個 inte***ce abc 包括了如下的方法 m():

public inte***ce abc

另外有個類 class1 繼承了 abc 並且擁有自己的方法 n():

public class class1 : abc

public void m()

public void n()

}程式中有如下語句:

// code #01

abc t = new class1();

t.m();

這種情況下編譯可以通過而且會輸出正確的結果。但是如果是下面的情況:

// code #02

abc t = new class1();

t.n();

編譯就會出錯,所以通過 abc t = new class1() 這句話我們得到的肯定不是 class1 的乙個例項。但是介面是不可以例項化的,那麼 abc t = new class1() 究竟例項化了乙個什麼東西?

1. 我是誰?

很久以前,成龍上演了一部《我是誰》,現在 t 也遭遇了相同的問題。成龍當時就不太幸運了,因為要喚醒人的記憶不是那麼容易;相比之下,t 就幸運的多了,因為它有元資料這張 id 卡。那麼,t 究竟是誰?

// code #03

abc t = new class1();

console.writeline(t.gettype());

你猜答案是什麼?是 class1!

2. 選擇性透過...

既然 t 指向 class1 的例項,為什麼 t.n() 不能通過編譯呢?如果你玩過 flash,你會知道 flash 的 mask 可以做出類似於聚光燈的效果,把聚光圈以外的東西統統隱藏起來。從目標物件的角度來看,介面利用這種「遮掩」的特性「遮蔽」了目標物件的部分功能;從客戶端的角度來看,介面就像細胞膜那樣有選擇性的讓目標物件的功能進入客戶端的作用範圍。

請看下圖:

(圖沒貼出來)

對應 code #01 和 code #02,t 發揮了介面的「選擇性透過」特性,僅讓客戶端和 class1 例項的 m() 接觸。

3. 噢,別這樣!

雖然 code #02 中的 t 確實指向了 class1 的例項,但編譯器卻不允許你呼叫 t.n(),因為 abc 並不認識 class1.n()。不過我們心知肚明 t 是有能力呼叫 n() 的,於是就去和編譯器溝通一下。最後我們和編譯器達成共識,讓 t 這樣呼叫 n():

// code #04

((class1)i).n();

正當你為讓 t 發揮了潛能而高興時,你卻聽到另外一種聲音:別這樣!為什麼?假如我們有這樣乙個方法:

// code #05

void process(abc abc)

某天不知道誰搞了乙個 class2:

// code #06

class class2 : abc

public void o()

}然後這個人把 class2 的例項傳遞給 process():

// code #07

abc t = new class2();

process(t);

那個人當然不知道我們在 process 裡面搞什麼鬼,但卻莫名其妙的得到乙個 invalidcastexception!

好吧,如果你需要在 process 裡面處理 class1 的例項,那你為什麼不直接把你的想法告訴別人呢?

// code #08

process(class1 c)

同樣的道理,如果我們希望呼叫 class1.n(),為什麼我們不直接做:

// code #09

class1 c = new class1();

c.n();

而要寫 code #02 那樣的**呢?

回顧 code #05,我們除了知道 abc 肯定有乙個 m() 之外,根本無從得知具體的例項還會有別的什麼方法可用,那我們憑什麼要求 code #02 可以通過編譯呢?

4. 我還應該說點什麼呢?

好吧,我們繞了乙個大圈,最後發現雖然 abc t = new class1() 無法通過編譯,但 t 確實指向乙個 class1 例項,只是這個例項好像被 t 搞得有點「低能兒」罷了。我認為真正的問題並不在於 t 究竟是什麼,而是在於我們為什麼要這樣使用介面。這是乙個很基礎的問題,除非你不打算在 oo 方面有所發展,否則你得把它弄清楚,要不然你真的會很麻煩,至少你會誤解介面的真正意義。

關於繼承的例項化

類裡面喲乙個很重要的屬性就是可以繼承其他的類的屬性,但有時候在繼承的時候會搞不清繼承之後的變數到底應該用哪乙個!下面就介紹一下 class animal object hobbly girl defrun self print self.hobbly print run.class dog anim...

關於 類的 virtual 例項 說明 (c )

using system using system.collections.generic using system.text public class classboy classfather public class classgirl classfather endregion region ...

原創 C 類的繼承

在c 語言中,乙個派生類可以從乙個基類派生,也可以從多個基類派生。從乙個基類派生的繼承稱為單繼承 從多個基類派生的繼承稱為多繼承。例 單繼承的定義 class b public 多繼承的定義 class c public a,private b 注 如果在基類前不寫訪問控制符,則預設為私有的 公有繼...