題外話(huà):因為類(lèi)六有關(guān)索引器的內容比較復雜,我想精心準備出經(jīng)典實(shí)例和通俗易懂的講解內容再發(fā)表博客,所以我先跳過(guò)索引器,接著(zhù)學(xué)習繼承。
本節課我們來(lái)學(xué)習一下類(lèi)的繼承,在面向對象二 中我已經(jīng)講述了繼承的概念、優(yōu)點(diǎn),但是沒(méi)有舉出具體的代碼實(shí)例講解,在這篇博客中,不會(huì )再次細致的講解繼承的原理,建議同學(xué)們最好是先閱讀面向對象二系列后,再學(xué)這篇博客,我們現在來(lái)回憶一下繼承的概念。
繼承
繼承是面向對象理論中最重要的一項機制,通過(guò)繼承一個(gè)現有的類(lèi),新創(chuàng )建的類(lèi)可以不需要再寫(xiě)任何代碼,就可以按照繼承來(lái)的父類(lèi)中的合適的訪(fǎng)問(wèn)權限直接擁有所繼承的類(lèi)的功能,同時(shí)還可以創(chuàng )建自己的專(zhuān)門(mén)功能。 就向我在面向對象二中提到的,繼承的優(yōu)點(diǎn)就是:當類(lèi)與類(lèi)中有共同的類(lèi)成員時(shí),完全可以提煉出共同的類(lèi)成員,單獨的編寫(xiě)一個(gè)類(lèi),讓其他的只要想包含這個(gè)類(lèi)中共同的類(lèi)成員的類(lèi)來(lái)繼承我們單獨編寫(xiě)的類(lèi),使得代碼可以共享,避免重復。
單獨編寫(xiě)的類(lèi)我們習慣的稱(chēng)為父類(lèi),或基類(lèi),而繼承這個(gè)父類(lèi)的類(lèi)我們稱(chēng)為子類(lèi)或派生類(lèi)。要想使用繼承,就必須注意到,當兩個(gè)類(lèi)A和B之間具備“B is A”就關(guān)系時(shí),就可以用到繼承,那么B就可以說(shuō)是A的子類(lèi)或派生類(lèi),A是B的父類(lèi)或基類(lèi)。我們不能把猴子和人看成存在繼承關(guān)系的兩個(gè)類(lèi),但是如果現在還有一個(gè)動(dòng)物類(lèi),那么猴子是動(dòng)物,人也是動(dòng)物,就可以把動(dòng)物作為人和猴子的父類(lèi)。
于此同時(shí),當我們要修改類(lèi)中共同的成員時(shí),只需要修改父類(lèi)中的共同類(lèi)成員,就能達到修改繼承這個(gè)父類(lèi)的子類(lèi)們的目的,而如果我們想單獨的修改子類(lèi)中的類(lèi)成員,是不會(huì )影響到父類(lèi)的,更不會(huì )影響到從父類(lèi)中繼承的其他子類(lèi)們,這說(shuō)明了繼承關(guān)系只會(huì )向下傳遞 ,子類(lèi)本身的調整并不會(huì )影響基類(lèi)。
請同學(xué)們注意,我說(shuō)的子類(lèi)們,說(shuō)明一個(gè)父類(lèi)可以有多個(gè)子類(lèi),但是一個(gè)子類(lèi)只可以繼承一個(gè)父類(lèi)(和多個(gè)接口,接口我會(huì )在下一篇博客中講解),以前聽(tīng)課的時(shí)候,每講到一個(gè)子類(lèi)只能有一個(gè)父類(lèi)時(shí),也就是說(shuō)一個(gè)兒子只能有一個(gè)爸爸時(shí),學(xué)生們就會(huì )搗亂,所以我也要養成一種這樣描述的習慣:就是“一個(gè)兒子類(lèi)只能有一個(gè)含DNA的親生父親類(lèi)”,相信這樣說(shuō)應該不會(huì )有什么疏漏了,DNA就是他們共同的類(lèi)成員,當然這個(gè)DNA也不可能完成一致,否則就是一個(gè)人了,也就沒(méi)有我們創(chuàng )建子類(lèi)的目的了,在程序繼承中我們把從父類(lèi)中繼承下來(lái)的用非private修飾,父親所獨有的用private修飾,同時(shí)就算兒子從父親那繼承下了的,我們也可以重新的再次賦值。
下面我們來(lái)看看繼承的基本語(yǔ)法:
class SonClassName:BaseClassName
{
}
其中的SonClassName為新創(chuàng )建的子類(lèi),BaseClassName為基類(lèi),符號“:”定義了兩個(gè)類(lèi)的繼承關(guān)系,也就是SonClassName類(lèi)繼承自BaseClassName類(lèi),通過(guò)繼承,子類(lèi)可以訪(fǎng)問(wèn)到基類(lèi)中的不法成員,基類(lèi)可以借助使用訪(fǎng)問(wèn)修飾符來(lái)有條件的開(kāi)放基類(lèi)的功能,供派生類(lèi)繼承。SonClassName類(lèi)包含了BaseClassName類(lèi)中所有非private修飾的類(lèi)成員,這里所提到的private指的是訪(fǎng)問(wèn)修飾符,因為訪(fǎng)問(wèn)修飾符 直接關(guān)系到繼承結構的限制,雖然面向對象二中也有具體的講解,這里我們還是再重溫一下:
public修飾符修飾的A類(lèi)類(lèi)成員,所有的非A類(lèi)的類(lèi)的方法中,都可以通過(guò)A類(lèi)的類(lèi)名(靜態(tài)的A類(lèi)成員)或A類(lèi)的對象a(實(shí)例的A類(lèi)成員)來(lái)訪(fǎng)問(wèn)。
protected修飾符修飾的A類(lèi)類(lèi)成員,在所有的A類(lèi)的子類(lèi)的方法中,都可以直接的訪(fǎng)問(wèn)到,不需要引用過(guò)程,而在所有的非A類(lèi)的類(lèi)的方法中,都無(wú)法訪(fǎng)問(wèn)。
private修飾符修飾的A類(lèi)類(lèi)成員,在所有的A類(lèi)的類(lèi)成員中,都可以直接的訪(fǎng)問(wèn)到(除嵌套類(lèi)),嵌套類(lèi)可以通過(guò)A類(lèi)的類(lèi)名(靜態(tài)的A類(lèi)成員)或A類(lèi)的對象a(實(shí)例的A類(lèi)成員)來(lái)訪(fǎng)問(wèn),而在所有的非A類(lèi)的類(lèi)的方法中,都無(wú)法訪(fǎng)問(wèn)。
可以看出,修飾符的權限逐步縮小,在編寫(xiě)繼承類(lèi)代碼時(shí),如果父類(lèi)中的成員,不需要外部類(lèi)來(lái)訪(fǎng)問(wèn),為了包含父類(lèi)的成員,盡量避免public修飾符的亂用,而是應該采用protected修飾符,會(huì )更加的安全、合理。
我們來(lái)看下面的實(shí)例,實(shí)例中包括四個(gè)類(lèi),一個(gè)包括入口方法的Program類(lèi),一個(gè)GFClass、一個(gè)FClass、一個(gè)SClass。在Program類(lèi)的Main方法中執行對SClass的實(shí)例化,創(chuàng )建son對象,我們來(lái)看看繼承的訪(fǎng)問(wèn)權限,特別是在創(chuàng )建son對象時(shí)構造方法的方法繼承順序。
1 namespace hello 2 { 3 // 創(chuàng )建一個(gè)爺爺類(lèi)GFClass 4 class GFClass 5 { 6 // 定義一個(gè)私有成員MyMoney,私有字段是無(wú)法被繼承的 7 int MyMoney = 5 ; 8 9 // 定義兩個(gè)受保護的字段,受保護的字段允許子類(lèi)訪(fǎng)問(wèn)到 10 protected string GFhouse = " 一套GFHouse房子 " ; 11 protected int GFMoney = 10 ; 12 13 // 定義爺爺類(lèi)的構造函數,這樣在創(chuàng )建爸爸類(lèi)和兒子類(lèi)的對象時(shí),都會(huì )先執行所以父類(lèi)以上的構造方法 14 public GFClass() 15 { 16 // 顯示出私有字段的值 17 Console.WriteLine( " 我是爺爺!我自己留點(diǎn)養老錢(qián):{0}萬(wàn),這是我自己的錢(qián),私有財產(chǎn)呀! " , MyMoney); 18 Console.WriteLine(); 19 } 20 21 // 定義一個(gè)爺爺類(lèi)中成員爺爺說(shuō)的方法,注意它是public的。 22 public void GFSay() 23 { 24 // 顯示出爺爺類(lèi)中的成員字段的值。 25 Console.WriteLine( " 我是爺爺!我給你們留下:{0},還留下:{1}萬(wàn). " , GFhouse, GFMoney); 26 } 27 } 28 29 // 創(chuàng )建父親類(lèi),繼承爺爺類(lèi) 30 class FClass : GFClass 31 { 32 // 定義一個(gè)靜態(tài)的公有的字段,目的是在Main方法中直接用父親類(lèi)的類(lèi)名引用出字段的值 33 public static int MyMoney = 5 ; 34 35 // 定義兩個(gè)受保護的字段,受保護的字段允許子類(lèi)訪(fǎng)問(wèn)到 36 // 注意Fhouse字段,在構造函數中,重新將繼承的爺爺類(lèi)的中的GFhouse字段值,賦給了Fhouse字段。 37 // 說(shuō)明GFhouse可以直接的訪(fǎng)問(wèn)到。 38 protected string Fhouse = " 無(wú)房子 " ; 39 protected int FMoney = 15 ; 40 41 // 定義父親類(lèi)的構造函數,這樣在創(chuàng )建兒子類(lèi)的對象時(shí),都會(huì )先執行所以父類(lèi)以上的構造方法 42 public FClass() 43 { 44 // 因為父親沒(méi)有房子,住的是爺爺的房子,就采用了Fhouse的值繼承GFhouse的值的方式傳遞下去, 45 // 放到了構造函數中,目的是只要創(chuàng )建父親類(lèi)或兒子類(lèi)的對象時(shí),繼承房子的事件就一定會(huì )發(fā)生。 46 Fhouse = GFhouse; 47 48 // 顯示出私有字段的值 49 Console.WriteLine( " 我是爸爸,我沒(méi)有房子!繼承了你爺爺的房子。我把財產(chǎn)拿出:{0}萬(wàn),做慈善,用我的名字去取。 " , MyMoney); 50 Console.WriteLine(); 51 } 52 53 // 定義一個(gè)爸爸類(lèi)中成員爸爸說(shuō)的方法,注意它是public的 54 public void FSay() 55 { 56 Console.WriteLine( " 我是爸爸,留下:{0}萬(wàn),你們爺爺留下來(lái)的錢(qián)我也沒(méi)動(dòng)。 " , FMoney); 57 Console.WriteLine(); 58 } 59 } 60 61 // 定義一個(gè)兒子類(lèi),繼承爸爸類(lèi),此處注意不能再繼承爺爺類(lèi),兒子類(lèi)中繼承了所有父親類(lèi)中的非private成員,爺爺類(lèi)中public成員 62 class SClass : FClass 63 { 64 // // 定義一個(gè)兒子類(lèi)中成員兒子說(shuō)的方法,注意它是public的 65 public void SSay() 66 { 67 // 可以直接訪(fǎng)問(wèn)到爺爺說(shuō)的方法,因為是public修飾的 68 Console.Write( " 爺爺對我說(shuō): " ); 69 GFSay(); 70 Console.WriteLine(); 71 // 可以直接訪(fǎng)問(wèn)到爸爸說(shuō)的方法,因為是public修飾的 72 Console.Write( " 爸爸對我說(shuō): " ); 73 FSay(); 74 Console.WriteLine(); 75 76 // 可以直接訪(fǎng)問(wèn)到爸爸的受保護字段Fhouse,因為有繼承爸爸類(lèi)的構造函數, 77 // 此時(shí)爸爸類(lèi)中的Fhouse的值不再是“無(wú)房子”,而是“一套GFhouse房子” 78 Console.WriteLine( " 我現在住的是,爸爸繼承下來(lái)的: " + Fhouse); 79 80 // 打印出兒子可以用的爺爺留下的錢(qián)和爸爸留下的錢(qián) 81 Console.WriteLine( " 我現在一共用的遺產(chǎn):{0}萬(wàn) " , FMoney + GFMoney); 82 } 83 } 84 class Program 85 { 86 static void Main( string [] args) 87 { 88 // 創(chuàng )建一個(gè)兒子類(lèi)的實(shí)例son 89 SClass son = new SClass(); 90 91 // 用對象son調用兒子說(shuō)的方法 92 son.SSay(); 93 Console.WriteLine(); 94 95 // 因為父親類(lèi)中的MyMoney字段是靜態(tài)的,所以使用父親類(lèi)的類(lèi)名引用 96 Console.WriteLine( " 我要把捐出爸爸留下的慈善金{0}萬(wàn) " ,FClass.MyMoney); 97 } 98 } 99 100 }
運行結果 我是爺爺!我自己留點(diǎn)養老錢(qián):5萬(wàn),這是我自己的錢(qián),私有財產(chǎn)呀!
我是爸爸,我沒(méi)有房子!繼承了你爺爺的房子。我把財產(chǎn)拿出:5萬(wàn),做慈善,用我的名字去取。
爺爺對我說(shuō):我是爺爺!我給你們留下:一套GFHouse房子,還留下:10萬(wàn).
爸爸對我說(shuō):我是爸爸,留下:15萬(wàn),你們爺爺留下來(lái)的錢(qián)我也沒(méi)動(dòng)。
我現在住的是,爸爸繼承下來(lái)的:一套GFHouse房子 我現在一共用的遺產(chǎn):25萬(wàn)
我要把捐出爸爸留下的慈善金5萬(wàn)
通過(guò)這個(gè)實(shí)例的注解,希望大家能夠明確的體會(huì )到訪(fǎng)問(wèn)權限的作用,不知道大家能不能發(fā)現一點(diǎn),就是第81行中能夠訪(fǎng)問(wèn)到爺爺類(lèi)中的protected成員GFMoney,這就說(shuō)明了protected也是允許隔代繼承的。
同學(xué)們可以在課下試試以下兩個(gè)操作:一,在GFClass中和FClass中定義的MyMoney是在其子類(lèi)中訪(fǎng)問(wèn)不到的,因為他們是private修飾的(在類(lèi)中缺省修飾符的字段都是private修飾的);二,在Main方法中,無(wú)法訪(fǎng)問(wèn)到GFClass中和FClass中定義的protected和private修飾的字段,驗證一下訪(fǎng)問(wèn)修飾符的權限作用。
構造方法的繼承
在這個(gè)實(shí)例中用到了構造方法的繼承,在繼承關(guān)系中,構造方法不同于一般的方法成員,基類(lèi)和派生類(lèi)的構造方法都是分別獨立的,在類(lèi)四 中我們講到了在創(chuàng )建A類(lèi)對象a時(shí),編譯器首先要做的就是對所有A類(lèi)的基類(lèi)以上的構造方法先執行一次,然后在執行自己的構造方法。 在類(lèi)四中,我只是舉了基類(lèi)中的構造器都是無(wú)參時(shí)的情況,其實(shí)繼承中構造方法的繼承是很復雜的,構造函數的繼承是很多企業(yè)面試題當中的重要考點(diǎn),下面我們來(lái)通過(guò)實(shí)例來(lái)總結一下構造方法的繼承原則:
如果在子類(lèi)的構造方法中,沒(méi)有任何的指定的繼承父類(lèi)的哪個(gè)構造方法時(shí),C#會(huì )默認的調用沒(méi)有參數的構造方法,同時(shí)我們要知道這樣一個(gè)機制,就是當一個(gè)類(lèi)中規定了有參的構造函數時(shí),無(wú)參的構造函數編譯器是不會(huì )再默認的創(chuàng )建了,所以為了避免子類(lèi)中出現無(wú)參的構造方法,我們最好是顯式的調用基類(lèi)的構造方法,必須最好養成在創(chuàng )建父類(lèi)時(shí),及時(shí)父類(lèi)的無(wú)參構造函數無(wú)作用,也應該把它寫(xiě)上去,避免子類(lèi)在創(chuàng )建對象時(shí),出現構造方法的向上繼承出現錯誤。
顯式的調用基類(lèi)的構造方法使用base關(guān)鍵字,如
public SonClass(int i,int j):base ([i,j])
{
}
其中base指的就是基類(lèi),base()指的就是基類(lèi)的構造方法,當然,“()”中代表的是參數。使用構造方法繼承時(shí)要注意兩個(gè)原則:一、子類(lèi)中構造方法有兩個(gè)參數,那么它有三種繼承父類(lèi)構造方法的方式:無(wú)參、一個(gè)參數、二個(gè)參數,當然父類(lèi)必須有這3種;二、如果父類(lèi)中只有一個(gè)無(wú)參構造方法的,而無(wú)其他構造方法時(shí),那么子類(lèi)中必須也構造一個(gè)無(wú)參的構造方法,這時(shí)這個(gè)有兩個(gè)參數的構造方法就只有會(huì )有一種父類(lèi)的無(wú)參構造方法的繼承。
下面我們來(lái)看這個(gè)例子體會(huì )我上面所說(shuō)的兩個(gè)原則:
1 // 定義一個(gè)父類(lèi)F 2 class F 3 { 4 // 定義F中的無(wú)參構造方法 5 public F() 6 { 7 Console.WriteLine( " 如果子類(lèi)中的構造器沒(méi)有明確的使用:base([…]),創(chuàng )建實(shí)例時(shí)將會(huì )出現我無(wú)參構造器! " ); 8 } 9 // 定義F中的有一個(gè)參構造方法 10 public F( string i) 11 { 12 Console.WriteLine( " 想在創(chuàng )建實(shí)例中出現我,必須在子類(lèi)的構造方法后使用:base(i) " ); 13 } 14 // 定義F中的有兩個(gè)參構造方法 15 public F( string i, string j) 16 { 17 Console.WriteLine( " 子類(lèi)中沒(méi)有使用:base(i,j)來(lái)繼承我這個(gè)構造方法,所以創(chuàng )建s2不會(huì )出現我這句話(huà) " ); 18 } 19 } 20 // 定義一個(gè)子類(lèi)S,繼承父類(lèi)F 21 class S:F 22 { 23 // 定義F中的無(wú)參構造方法 24 // 如果子類(lèi)中定義了無(wú)參構造器,那么父類(lèi)中一定也要定義無(wú)參構造器, 25 // 因為如果父類(lèi)中有有參構造器后,編譯器默認的無(wú)參構造器就會(huì )失去. 26 public S() 27 { 28 Console.WriteLine( " 有我就必須規定父類(lèi)的無(wú)參構造器 " ); 29 } 30 31 // 定義S中的有一個(gè)參構造方法,沒(méi)有繼承用父類(lèi)中的有參構造。 32 public S( string i) 33 { 34 Console.WriteLine(i); 35 } 36 37 // 定義了兩個(gè)參數的子類(lèi)構造方法,繼承了一個(gè)參數的構造方法 38 // 此處說(shuō)明,子類(lèi)可以根據base(參數)中參數的個(gè)數,調用父類(lèi)中的相應的構造器 39 // 如果缺省的時(shí)候,就會(huì )調用無(wú)參的構造器。 40 public S( string i, string j): base (i) 41 { 42 Console.WriteLine( " 我沒(méi)有使用:base(i,j)來(lái)繼承父類(lèi)兩參構造方法,繼承一個(gè)參數的構造方法,所以創(chuàng )建s2時(shí)只會(huì )出現調用父類(lèi)的有一個(gè)參構造方法 " ); 43 } 44 45 } 46 class Program 47 { 48 static void Main( string [] args) 49 { 50 // 會(huì )調用兩個(gè)無(wú)參的構造方法 51 S s = new S(); 52 Console.WriteLine( " ------- " ); 53 54 // 因為子類(lèi)的一參構造方法沒(méi)有直接調用父類(lèi)中的一參構造方法,所以結果應該是調用父無(wú)參和子一參 55 S s1 = new S( " 我是s1,調用了父類(lèi)無(wú)參構造器和本類(lèi)中使用一參構造器 " ); 56 Console.WriteLine( " ------- " ); 57 58 // 因為子類(lèi)的兩參構造方法直接調用父類(lèi)中的一參構造方法,所以結果應該是調用父一參和子兩參 59 S s2 = new S( " 使用兩參構造器 " , " 注意父類(lèi)的出現的構造方法 " ); 60 Console.WriteLine( " ------- " ); 61 } 62 }
結果如下: 如果子類(lèi)中的構造器沒(méi)有明確的使用:base([…]),創(chuàng )建實(shí)例時(shí)將會(huì )出現我無(wú)參構造器!
有我就必須規定父類(lèi)的無(wú)參構造器 ------- 如果子類(lèi)中的構造器沒(méi)有明確的使用:base([…]),創(chuàng )建實(shí)例時(shí)將會(huì )出現我無(wú)參構造器!
我是s1,調用了父類(lèi)無(wú)參構造器和本類(lèi)中使用一參構造器 ------- 想在創(chuàng )建實(shí)例中出現我,必須在子類(lèi)的構造方法后使用:base(i) 我沒(méi)有使用:base(i,j)來(lái)繼承父類(lèi)兩參構造方法,繼承一個(gè)參數的構造方法,所以創(chuàng )建s 2時(shí)只會(huì )出現調用父類(lèi)的有一個(gè)參構造方法 ------- 請按任意鍵繼續. . .
看了上面的例子,相信大家應該會(huì )使用構造方法的繼承了,使用過(guò)程一定要注意那兩個(gè)原則。
Object類(lèi)
在c#中繼承扮演了很重要的角色,所有的類(lèi)至少都會(huì )繼承一個(gè)基類(lèi)Object類(lèi),當一個(gè)類(lèi)沒(méi)有明確的注明是繼承那個(gè)類(lèi)時(shí),它自身是繼承Object類(lèi)的,這時(shí)同學(xué)們就會(huì )應該考慮這樣一個(gè)問(wèn)題,為什么我們在創(chuàng )建一個(gè)沒(méi)有指明繼承哪個(gè)類(lèi)的對象時(shí),對象中會(huì )不會(huì )包含Object類(lèi)的方法呢?
答案是一定的,我們來(lái)看上一個(gè)實(shí)例,在S類(lèi)和F父類(lèi)中,除了構造方法沒(méi)有定義任何類(lèi)成員,在我們創(chuàng )建s時(shí),點(diǎn)的時(shí)候也就是引用s的成員時(shí),會(huì )出現四個(gè)成員:
S類(lèi)因為繼承了F類(lèi),就無(wú)法再繼承其他類(lèi)了,怎么會(huì )用這四個(gè)Object類(lèi)的成員,說(shuō)明了什么呢?當S的父類(lèi)F類(lèi)因為沒(méi)有明確的繼承類(lèi),就繼承了Object類(lèi),F中包括了這四個(gè)類(lèi),所以S類(lèi)中也包括了Object類(lèi)的成員。我們可以這樣說(shuō)Object類(lèi)是任何類(lèi)的基類(lèi),即使你的有自己的父類(lèi),也的能夠用到Object類(lèi)的成員的,均會(huì )繼承Object類(lèi)的所有基本功能。
Object類(lèi)位于類(lèi)庫的System命名空間下,本身提供了下面六個(gè)方法成員:
Equals:用來(lái)判斷調用此方法的對象與指定的對象是否相同,返回True和False來(lái)代表相同和不同。
GetHashCode:特定類(lèi)的哈希函數,用于哈希演算與類(lèi)似哈希表的數據表結構。
GetType:取得目前實(shí)例對象的類(lèi)
ReferenceEquals:比較指定的對象是否引用到相同的實(shí)例。
ToString:轉換為字符串的方法。
Finalize:在垃圾回收機制開(kāi)始執行前,給對象提供進(jìn)行對象資源釋放或是清空操作的機會(huì )。
我用下面的例子來(lái)講述其中3種常見(jiàn)用法:
1 // 定義一個(gè)F類(lèi) 2 class F 3 { 4 // 定義一個(gè)公有的i字段 5 public int i; 6 } 7 class Program 8 { 9 static void Main( string [] args) 10 { 11 // 創(chuàng )建F類(lèi)的兩個(gè)對象f和f1 12 F f = new F(); 13 F f1 = new F(); 14 // 使用Equals方法,判斷f是否是f1 15 Console.WriteLine( " 對象f是否是對象f1: " + f.Equals(f1)); 16 Console.WriteLine(); 17 18 // 定義一個(gè)Object類(lèi)型的type變量使用GetType方法接收i的數據類(lèi)型,打印出來(lái) 19 object type = f.i.GetType(); 20 Console.WriteLine( " i的類(lèi)型是 " + type); 21 Console.WriteLine(); 22 23 // 使用.ToString()方法將i轉換為字符串類(lèi)型,再用GetType方法接收i的數據類(lèi)型,打印出來(lái) 24 Console.WriteLine( " i的類(lèi)型是 " + f.i.ToString().GetType()); 25 } 26 } 27
結果如下: 對象f是否是對象f1:False
i的類(lèi)型是System.Int32
i的類(lèi)型是System.String
實(shí)際上這六種方法是public的修飾的虛方法,關(guān)于虛方法的定義,我們下節課類(lèi)八繼承中的多態(tài)性:方法重寫(xiě)。我們將講解到。