小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

c#基礎(chǔ)五 面向?qū)ο蟾呒壘幊蹋ǚ庋b 繼承 多態(tài) 抽象類 密封類 接口)

 細(xì)想生活 2015-01-19

1.類的繼承與多態(tài)性

1.1基類和擴充類

       C#實現(xiàn)繼承的方式:類繼承和接口繼承

       繼承用冒號(:)表示。被繼承的叫做父類或者基類,從基類繼承的類叫擴充類,又叫派生類或子類。所有類的基類System.Object

聲明方式:[訪問修飾符] class 擴充類名稱:基類名稱

     {    

     }

  若B繼承自A,也可以使用強制轉(zhuǎn)換操作將其轉(zhuǎn)換為A 對象。如:

  A b = (A)new B();或者 A b = new B();此時,B對象將被限制為A 對象的數(shù)據(jù)和行為,而無法再訪問B對象中的數(shù)據(jù)和行為,除非A中的方法被B重載,將會訪問B 的方法。將B強制轉(zhuǎn)換為A后,還可以將A重新轉(zhuǎn)換為B,但是,并非A的所有實例在任何情況下都可強制轉(zhuǎn)換為B,只有實際上是B的實例的那些實例才可以強制轉(zhuǎn)換為B。

       擴充類不能繼承基類中定義的private方法,只能繼承基類的public成員或者protected成員。

       初始化基類時,會首先調(diào)用基類的構(gòu)造函數(shù)再調(diào)用擴充類的構(gòu)造函數(shù)

1.2 多態(tài)性

       定義:同一操作作用于不同類的實例,不同的類將進行不同的解釋,最后產(chǎn)生不同的結(jié)果。即:建立一個父類的對象,它的內(nèi)容可以是這個父類的,也可以是這個子類的,子類和父類都定義有同樣的方法;當(dāng)使用對象調(diào)用這個方法的時候,父類里的同名對象將被調(diào)用,當(dāng)在父類的這個方法前加virtual關(guān)鍵字,子類的同名方法將被調(diào)用。

       實現(xiàn)多態(tài)的方法:

              1.通過繼承實現(xiàn)。多個類可以繼承自同一個類,每個擴充類可根據(jù)重寫基類成員以提供不同的功能。

              2.通過抽象類實現(xiàn)。抽象類本身不能被實例化,只能在擴充類中通過繼承使用。抽象類的部分或全部成員不一定都要實現(xiàn),但要在繼承類中全部實現(xiàn),抽象類中已實現(xiàn)的成員扔可以被重寫,并且繼承類仍可以實現(xiàn)其他功能。

              3.通過接口實現(xiàn)。接口僅聲明類需要實現(xiàn)的方法、屬性、事件;以及每個成員需要接受和返回的參數(shù)類型,而他們的特定實現(xiàn)需要實現(xiàn)類去完成。

  • 虛擬(virtual)和重寫(override)

C#中,如果基類的某個功能不滿足要求,可以在擴充類中重寫基類的方法實現(xiàn)新的功能,

復(fù)制代碼
復(fù)制代碼
 1 class A
2
3 {
4
5 public virtual string MyProperty { get; set; }//擴充類可以重寫此屬性
6
7 static void Main(string[] args)
8
9 {
10
11 }
12
13 public virtual void myMethod()//擴充類可以重寫此方法
14
15 {
16
17 }
18
19 }
20
21 class B : A
22
23 {
24
25 public override void myMethod()//基類中也可以不重寫此方法
26
27 {
28
29 }
30
31 }
復(fù)制代碼
復(fù)制代碼

注意:(1)虛擬方法不能聲明 為靜態(tài)的。因為靜態(tài)的方法是應(yīng)用在類一層次的,而面向?qū)ο蟮亩鄳B(tài)性只能在對象上運作,所以無法在類中使用。此外,override,abstract也不能跟static共存.

       (2)virtual 不能喝private 一起使用,否則無法在擴充類中重寫。

       (3)重寫方法的名稱、參數(shù)個數(shù)、類型以及返回值都必須和虛擬方法一致。

  • 隱藏

只有在擴充類中使用override修飾符時,才能重寫基類聲明為virtual的方法;否則,在繼承的類中聲明一個與基類方法同名的方法會隱藏基類的方法。

與方法或?qū)傩圆煌氖?,使用new關(guān)鍵字時并不要求基類中的方法或?qū)傩月暶鳛関irtual,只要在擴充類的方法或?qū)傩郧奥暶鳛閚ew,就可以隱藏基類的方法或?qū)傩?。理解:新方法把老方法(相對于子類)隱藏,但老方法仍可見。

舉例:

父:實例:b,

子:實例 d;

(1)父方法:無virtual;子方法:new;此時若強制轉(zhuǎn)換b=d,b.方法 調(diào)用父中方法

(2)父方法:有virtual;子方法:new;此時若強制轉(zhuǎn)換b=d,b.方法 調(diào)用父中方法

(3)父方法:有virtual;子方法:override;此時若強制轉(zhuǎn)換b=d,b.方法 調(diào)用子類中方法

什么時候用隱藏呢?

       如開發(fā)人員A需要重新設(shè)計基類中的某個方法,該基類是一年前由另一組開發(fā)人員設(shè)計的,并且已經(jīng)交給用戶使用,可是原來的開發(fā)人員在方法前沒有加virtual關(guān)鍵字,但又不允許修改原來的程序,這是無法用override重寫基類的方法,這是就需要隱藏基類的方法。

  • 在擴充類中直接調(diào)用基類的方法

可以在擴充類中用關(guān)鍵字base直接調(diào)用基類的方法。

復(fù)制代碼
 1 class B
2
3 {
4
5 public virtual int myMethod()
6
7 {
8
9 return 5;
10
11 }
12
13 }
14
15 class C : B
16
17 {
18
19 public override int myMethod()
20
21 {
22
23 return base.myMethod()*4;
24
25 }
26
27 }
復(fù)制代碼

1.3抽象類

       使用abstract修飾符,若類中的方法或?qū)傩詾?/strong>abstract,類必須用abstract修飾。只能用作基類,抽象方法沒有實現(xiàn)代碼(無大括號!)

抽象類和非抽象類的區(qū)別:

(1)抽象類不能直接被實例化,只能在擴充類中通過繼承使用

(2)抽象類可以包含抽象成員,非抽象類不能包含抽象成員

當(dāng)從抽象類派生非抽象類時,非抽象類必須實現(xiàn)抽象類的所有(必須是所有?。?/strong>抽象成員,當(dāng)然,如果繼承抽象類的也是抽象類就不必實現(xiàn)其抽象成員,由最后一個非抽象類實現(xiàn)。

復(fù)制代碼
 1   abstract class B
3 {
5 public abstract int BMethod();
6
7 }
8
9 abstract class C : B
10
11 {
13 public int CMethod()
14
15 {
16
17 return 4;
18
19 }
20
21 }
22
23 class D : B
24
25 {
27 public override int BMethod()
28
29 {
30
31 return 1;
32
33 }
34
35 }
復(fù)制代碼

什么時候使用抽象類呢?

如果有一個通用方法,對所有擴充類來說都是公共的,并且強制要求所有擴充類都必須實現(xiàn)這個方法,這種情況下就可以把該方法定義為基類中的抽象方法。

1.4 密封類

密封類是不能被其他類繼承的類,用sealed關(guān)鍵字聲明。sealed關(guān)鍵字也可以限制基類中的方法,防止被擴充類重寫,若類中的方法是sealed,該類不是必須用sealed來修飾的。帶有sealed修飾符的方法稱為密封方法,sealed方法必須和override關(guān)鍵字一起使用。

一般情況下,只有在某個方法重寫了基類中同名的方法,但又不希望該方法所在的類的擴充類重寫該方法,就可以在該方法前使用修飾符sealed。

復(fù)制代碼
 1 abstract class B
2
3 {
4
5 public abstract int BMethod();
6
7 }
8
9 class D : B
10
11 {
12
13 public override sealed int BMethod()//BMethod方法將不能再被重寫
14
15 {
16
17 return 1;
18
19 }
20
21 }
復(fù)制代碼

1.5 繼承過程中構(gòu)造函數(shù)的處理

在擴充類中,繼承了所有基類中聲明的public或protected成員。但是構(gòu)造函數(shù)則排除在外,不會被繼承下來。

為什么不繼承基類的構(gòu)造函數(shù)呢?因為構(gòu)造函數(shù)的主要用途是對類的成員初始化,包括對私有成員的初始化。如果讓構(gòu)造函數(shù)也能繼承,由于擴充類中無法訪問基類的私有成員,因此會導(dǎo)致創(chuàng)建擴充類的實例時無法對基類的私有成員進行初始化工作,從而導(dǎo)致程序運行失敗。為了解決這個問題,c#在內(nèi)部按照下列順序處理構(gòu)造函數(shù):從擴充類依次向上尋找基類,直到找到最初的基類,然后開始執(zhí)行最初的基類的構(gòu)造函數(shù)、再依次向下執(zhí)行擴充類的構(gòu)造函數(shù),直至執(zhí)行完最終的擴充類的構(gòu)造函數(shù)為止。

如下代碼會發(fā)生“A方法沒有0個參數(shù)的重載”錯誤,這是因為創(chuàng)建B的實例時,編譯器會尋找基類A中提供的無參數(shù)的構(gòu)造函數(shù),而A中沒有,從而報錯。

復(fù)制代碼
 1 class Program
2
3 {
4
5 static void Main(string[] args)
6
7 {
8
9 B b = new B(10);
10
11 Console.ReadLine();
12
13 }
14
15 }
16
17 class A
18
19 {
20
21 private int age;
22
23 public A(int age1)
24
25 {
26
27 this.age = age1;
28
29 }
30
31 }
32
33 class B : A
34
35 {
36
37 private int age;
38
39 public B(int age1)
40
41 {
42
43 this.age = age1;
44
45 }
46
47 }
復(fù)制代碼

       要解決這個問題,需將public B(int age1)改為public B(int age1):base(age1)即可。程序執(zhí)行時,會先調(diào)用System.Object的構(gòu)造函數(shù),然后調(diào)用A的帶參數(shù)的構(gòu)造函數(shù),由于B的構(gòu)造函數(shù)已經(jīng)將age1參數(shù)傳遞給A,所以A的構(gòu)造函數(shù)就可以利用這個傳遞的參數(shù)進行初始化。

2.版本控制

所有的方法默認(rèn)都是非虛擬的,調(diào)用非虛擬方法時不會受到版本的影響。若基類中聲明一個虛擬方法,而擴充類的方法中使用了override關(guān)鍵字,則執(zhí)行時會調(diào)用擴充類中的方法;若沒有使用override關(guān)鍵字,則調(diào)用基類的方法。而沒有聲明為virtual的非虛擬方法,則在編譯時就確定了應(yīng)該調(diào)用哪個方法了。

View Code

另外,若B繼承自A,C繼承自B,那么A中的virtual方法,B中override后,C中還可以繼續(xù)override。即 被override修飾的方法后就默認(rèn)為virtual,即virtual具有傳遞性。

3.接口

接口像一個抽象類,不過,接口是完全抽象的集合成員,主要特點是 只有聲明部分,沒有實現(xiàn)部分。一般用I開頭,接口中只能包含:(1)方法 屬性 索引器和事件的聲明,(2)不能包含構(gòu)造函數(shù)(因為無法構(gòu)建不能實例化的對象)(3)不能包含字段(因為字段隱含了某系內(nèi)部的執(zhí)行方法)(4)不能包含任何實現(xiàn)代碼(5)接口中的方法必須都是public的,因此不能再用public修飾符聲明。

       接口的用途是表示設(shè)計者和調(diào)用者的一種約定。例如,提供某個方法用什么名字、需要哪些參數(shù)、以及每個參數(shù)的類型。抽象類和接口的一個主要差別:類可以繼承多個接口,但只能繼承一個抽象類。

       使用接口還是抽象類來為組件提供多態(tài)性主要考慮以下幾個方面:

       (1)如果預(yù)計要創(chuàng)建組件的多個版本,則創(chuàng)建抽象類。抽象類提供簡單易行的方法來控制組件版本。通過更新基類,是所有繼承類都自動更新。另一方面,為了保護為使用接口而編寫的現(xiàn)有系統(tǒng),要求接口一旦創(chuàng)建就不能更改。如果需要接口的新版本,必須創(chuàng)建一個新的接口

       (2)如果創(chuàng)建的功能將在大范圍的完全不同的對象間使用,則使用接口。抽象類應(yīng)主要用于關(guān)系密切的對象,而接口最適合為不相關(guān)的類提供通用功能。

       (3)如果要設(shè)計小而精煉的功能塊,則使用接口;如果要設(shè)計大的功能單元,則使用抽象類,設(shè)計優(yōu)良的接口往往很小且相互獨立,減少了發(fā)生性能問題的可能。

       (4)如果要在組件的所有實現(xiàn)間提供通用的已實現(xiàn)的功能,則使用抽象類,抽象類允許部分實現(xiàn)類,而接口不包含任何成員的實現(xiàn)。

接口的聲明與實現(xiàn):

聲明:

[訪問修飾符] interface 接口名稱

{

//接口體

}

實現(xiàn)某個接口的任何類都將擁有該接口中所有元素,因此,當(dāng)需要再不相關(guān)的類中實現(xiàn)同樣的功能時,就可以使用接口。

View Code

顯示方式實現(xiàn)接口:

由于不同接口中的方法可以重名,因此,在一個類中實現(xiàn)接口中的方法時就存在著多義性,這時可以顯示實現(xiàn)接口中的方法,對于顯示實現(xiàn)的方法,不能通過類的實例訪問,而必須使用接口的實例。

View Code
復(fù)制代碼

小總結(jié)

封裝優(yōu)點:

  1. 良好的封裝能夠減少耦合
  2. 類內(nèi)部的實現(xiàn)可以自由的修改
  3. 類具有清晰的對外接口

繼承優(yōu)點:

1.使得所有子類公共的部分都放在了父類,使得代碼得到了共享,就避免了重復(fù)

2.繼承可使得修改或擴展繼承而來的實現(xiàn)代碼都較為容易。

缺點:

父類變,子類不得不變,繼承會破壞包裝,父類實現(xiàn)細(xì)節(jié)暴露給子類,其實是增大了兩個類之間的耦合性。

注意:c#中,子類從它的父類中繼承的成員有方法,域,屬性,事件,索引指示器,但構(gòu)造方法只能被調(diào)用不能繼承??梢杂胋ase關(guān)鍵字調(diào)用父類的成員。當(dāng)兩個類之間具備“is-a”關(guān)系時,就可以考慮用繼承。

 

多態(tài)特點:

1.子類以父類的身份出現(xiàn)

2.子類在工作時以自己的方式來實現(xiàn)

3.子類以父類身份出現(xiàn)時,子類特有的屬性和方法不可以使用

要實現(xiàn)多態(tài),要將父類聲明為虛方法,子類將方法重寫:override

注意:

重載:一般在類內(nèi)部,在不改變原方法的基礎(chǔ)上,增加新功能;兩個方法必須要方法名相同,但參數(shù)類型或個數(shù)必須要有所不同。

重寫:一般在不同的類中,必須要跟重寫的方法返回類型及參數(shù)個數(shù)及類型都相同,需要加override關(guān)鍵字,被重寫的方法要加      virtual關(guān)鍵字。

 

 

抽象類和接口的區(qū)別:

表面上看:1.抽象類可以給出一些成員的實現(xiàn),而接口不包含任何成員的實現(xiàn)

         2.抽象類的抽象成員可被子類部分實現(xiàn),而接口的成員需要實現(xiàn)類完全實現(xiàn)

         3.一個類只能繼承一個抽象類,但可實現(xiàn)多個接口

深層次:  1 .類是對對象的抽象,抽象類是對類的抽象(類相關(guān)性),接口是對行為的抽象(行為相關(guān)性)

         2.對于行為跨越不同類的對象,可使用接口;對于一些相似的類對象,用繼承抽象類

         3.從設(shè)計角度講,抽象類是從子類中發(fā)現(xiàn)了公共的東西,泛化出父類,然后子類繼承父類;而接口是根本不知子類的存在,方法如何實現(xiàn)還不確定,預(yù)先定義。

抽象類往往是通過 重構(gòu) 得來的,是自底而上抽象出來的,而接口則是自頂向下設(shè)計出來的。

復(fù)制代碼

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多