版權說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權,請進行舉報或認領
文檔簡介
C#程序設計第4章面向對象的高級特性目錄4.1案例引入 4.2面向對象的三大特性4.3類的繼承 4.4構造函數(shù)的執(zhí)行4.5訪問修飾符 4.6類的多態(tài) 4.7密封類4.8抽象類4.9接口4.10委托與事件4.11案例完成4.1案例引入
在交通工具的體系圖(圖4.1)中,我們可以看到,交通工具類細分可以分為客車、貨車、自行車、板車等車型,客車類具有交通工具類所有的基本信息。前面,我們學習客車類的定義,現(xiàn)在如果要在客車類的基礎上,派生出新的車型,一個是出租車,出租車除了具有客車類的一些特性外,還有它本身的每公里的價格跟喇叭聲特性,一個是公共汽車,它具有自身的喇叭聲特性。如何讓代碼盡可能簡潔?如何讓所有客車的派生類都提供車重、車牌號和輸出車相關信息的方法?汽車超速時如何警示?4.2面向對象的三大特性
面向對象的三個基本特征是:繼承、封裝、多態(tài)。
繼承:面向對象編程(OOP)語言的一個主要功能就是“繼承”。繼承是指這樣一種能力:它可以使用現(xiàn)有類的所有功能,并在無需重新編寫原來的類的情況下對這些功能進行擴展。通過繼承創(chuàng)建的新類稱為“子類”或“派生類”。被繼承的類稱為“基類”、“父類”或“超類”。繼承的過程,就是從一般到特殊的過程。
4.2面向對象的三大特性
封裝:封裝是面向對象的特征之一,是對象和類概念的主要特性。封裝,也就是把客觀事物封裝成抽象的類,并且類可以把自己的數(shù)據(jù)和方法只讓可信的類或者對象操作,對不可信的進行信息隱藏。在C#語言中,可以使用修飾符public、internal、protected、private分別修飾類的字段、屬性和方法。4.2面向對象的三大特性
多態(tài):多態(tài)性是允許你將父對象設置成為和一個或更多的他的子對象相等的技術,賦值之后,父對象就可以根據(jù)當前賦值給它的子對象的特性以不同的方式運作。4.3類的繼承 繼承是面向對象程序設計的主要特征之一,它可以讓您重用代碼,可以節(jié)省程序設計的時間。繼承就是在類之間建立一種相交關系,使得新定義的派生類的實例可以繼承已有的基類的特征和能力,而且可以加入新的特性或者是修改已有的特性建立起類的新層次。
現(xiàn)實世界中的許多實體之間不是相互孤立的,它們往往具有共同的特征也存在內(nèi)在的差別。人們可以采用層次結構來描述這些實體之間的相似之處和不同之處。在案例中反映了交通工具類的派生關系。最高層的實體往往具有最一般最普遍的特征,越下層的事物越具體,并且下層包含了上層的特征。它們之間的關系是基類與派生類之間的關系。4.3類的繼承 繼承的定義和使用:在現(xiàn)有類(稱為直接基類、父類)上建立新類(稱為派生類、子類)的處理過程稱為繼承。子類自動獲得父類的所有屬性和方法,而且可以在子類中添加新的屬性和方法。通過繼承創(chuàng)建子類的語法是:<訪問修飾符>class派生類名:基類名{//類的代碼}C#中,派生類從它的直接基類中繼承成員:方法、域、屬性、事件、索引指示器。除了構造方法和析構方法,派生類隱式地繼承了直接基類的所有成員。例4-1:派生類繼承基類4.3類的繼承 namespacech4_1{classVehicle//定義交通工具(汽車)類{protectedintwheels;//公有成員:輪子個數(shù)protectedfloatweight;//保護成員:重量publicVehicle(){}publicVehicle(intw,floatg){wheels=w;weight=g;}4.3類的繼承 publicvoidSpeak(){Console.WriteLine("交通工具的輪子個數(shù)是可以變化的!");}}classCar:Vehicle//定義轎車類:從汽車類中繼承{intpassengers;//私有成員:乘客數(shù)publicCar(intw,floatg,intp):base(w,g){wheels=w;weight=g;passengers=p;}}4.3類的繼承 classProgram{staticvoidMain(string[]args){}}}4.3類的繼承 Vehicle作為基類,體現(xiàn)了"汽車"這個實體具有的公共性質:汽車都有輪子和重量。Car類繼承了Vehicle的這些性質,并且添加了自身的特性:可以搭載乘客。C#中的繼承主要有以下幾種特性。1、繼承是可傳遞的。如果C從B中派生,B又從A中派生,那么C不僅繼承了B中聲明的成員,同樣也繼承了A中的成員。Object類作為所有類的基類。2、派生類應當是對基類的擴展。派生類可以添加新的成員,但不能除去已經(jīng)繼承的成員的定義。3、構造函數(shù)和析構函數(shù)不能被繼承。除此以外的其它成員,不論對它們定義了怎樣的訪問方式,都能被繼承。基類中成員的訪問方式只能決定派生類能否訪問它們。4、派生類如果定義了與繼承而來的成員同名的新成員,就可以覆蓋已繼承的成員。但這并不因為這派生類刪除了這些成員,只是不能再訪問這些成員。5、類可以定義虛方法、虛屬性以及虛索引指示器,它的派生類能夠重載這些成員,從而實現(xiàn)類可以展示出多態(tài)性。6、派生類只能從一個類中繼承,可以通過接口實現(xiàn)多重繼承。4.3類的繼承下面的代碼是一個子類繼承父類的例子:例4-2子類繼承父類namespacech4_2{publicclassParentClass{publicParentClass(){Console.WriteLine("父類構造函數(shù)。");}publicvoidprint(){Console.WriteLine("I'maParentClass。");}}4.3類的繼承publicclassChildClass:ParentClass{publicChildClass(){Console.WriteLine("子類構造函數(shù)。");}publicstaticvoidMain(){ChildClasschild=newChildClass();child.print();Console.ReadKey();}}}4.3類的繼承程序運行輸出結果:
父類構造函數(shù)。
子類構造函數(shù)。I'maParentClass。上面的一個類名為ParentClass,main函數(shù)中用到的類名為ChildClass。要做的是創(chuàng)建一個使用父類ParentClass現(xiàn)有代碼的子類ChildClass。
1.首先必須說明ParentClass是ChildClass的基類。
這是通過在ChildClass類中作出如下說明來完成的:"publicclassChildClass:ParentClass"。在派生類標識符后面,用分號":"來表明后面的標識符是基類。C#僅支持單一繼承。因此,你只能指定一個基類。
4.3類的繼承2.ChildClass的功能幾乎等同于ParentClass。
因此,也可以說ChildClass"就是"ParentClass。在ChildClass的Main()方法中,調用print()方法的結果,就驗證這一點。該子類并沒有自己的print()方法,它使用了ParentClass中的print()方法。在輸出結果中的第三行可以得到驗證。
3.基類在派生類初始化之前自動進行初始化。ParentClass類的構造函數(shù)在ChildClass的構造函數(shù)之前執(zhí)行。繼承是軟件復用的一種形式。使用繼承可以復用現(xiàn)有類的數(shù)據(jù)和行為,為其賦予新功能而創(chuàng)建出新類。復用節(jié)省了程序開發(fā)時間,能重用經(jīng)過實踐檢驗和調試的高質量代碼,提高系統(tǒng)的質量。4.4構造函數(shù)的執(zhí)行 當一個類的構造函數(shù)執(zhí)行時,它會初始化類的靜態(tài)成員和實例成員。如果派生類繼承了父類,我們會看到派生類對象有一部分就是基類對象。
要創(chuàng)建對象的基類部分,基類的一個構造函數(shù)被作為創(chuàng)建實例過程的一部分被調用。繼承層次鏈中的每個類在執(zhí)行它自己的構造函數(shù)之前執(zhí)行它的基類的構造函數(shù)。當一個實例被創(chuàng)建時,完成的第一件事是初始化對象的所有實例成員。在此之后,基類的構造函數(shù)被調用,然后該類自己的構造函數(shù)才被執(zhí)行。默認情況下,在對象被構造時,基類的無參數(shù)構造函數(shù)被調用。但構造函數(shù)可以被重載,所以基類可能有一個以上的構造函數(shù)。如果希望派生類使用一個指定的基類構造函數(shù)而不是無參數(shù)構造函數(shù),必須在構造函數(shù)初始化語句中指定它。有兩種形式的構造函數(shù)初始化語句:第一種形式使用關鍵字base并指明使用哪一個基類構造函數(shù)。第二種形式使用關鍵字this并指明應該使用當前類的哪一個另外的構造函數(shù)。基類構造初始化語句放在冒號后面,冒號緊跟著類的構造函數(shù)聲明的參數(shù)列表。構造函數(shù)初始化語句由關鍵字base和要調用的基類構造函數(shù)的參數(shù)列表組成。4.4構造函數(shù)的執(zhí)行 例4-3:base關鍵字namespacech4_3{publicclassA{publicA(){}publicA(stringa){}}publicclassB:A{publicB():base(){}}
classProgram{staticvoidMain(string[]args){}}}4.4構造函數(shù)的執(zhí)行 例4-4:this關鍵字namespacech4_4{publicclassStudent{publicstringstudentid;publicstringname;publicStudent(stringstudentid){this.studentid=studentid;}
4.4構造函數(shù)的執(zhí)行 publicStudent(stringstudentid,stringname):this(studentid){=name;}}
classProgram{staticvoidMain(string[]args){}}}4.4構造函數(shù)的執(zhí)行 4.5訪問修飾符 封裝性是面向對象編程的特征之一。它面對用戶簡化了內(nèi)部實現(xiàn)的細節(jié),將描述客觀事物的一組數(shù)據(jù)和操作組裝在一起,對外提供特定的功能。這仿佛就是一個黑箱,并不需要去了解實現(xiàn)的細節(jié)。在本節(jié)中,將介紹封裝的用途和實現(xiàn)。在生活中,使用一些東西的時候,根本不知道它的功能到底是如何實現(xiàn)的,但是能用好它提供的功能。可以說,這樣的東西進行了實現(xiàn)功能過程的封裝。在計算機程序中,也有封裝,它將抽象得到的數(shù)據(jù)和行為(或功能)相結合,形成了一個有機的整體,然后提供給用戶。封裝的目的是增強安全性和簡化編程,使用者不必了解具體的實現(xiàn)細節(jié),而只是通過外部接口調用功能.將對象進行封裝,并不等于是將整個對象完全包裹起來,而是根據(jù)實際需要,設置一定的訪問權限,用戶根據(jù)不同的權限調用對象提供的功能。在C#語言中,可以使用修飾符public、internal、protected、private分別修飾類的字段、屬性和方法。下面通過實例來介紹類的封裝性在實際中的應用。封裝性是OOP編程的重要特征。將類進行了封裝,對外提供可訪問的屬性和方法。外部對象必須通過這些屬性和方法訪問此對象的信息。4.5訪問修飾符 4.5.1類的可訪問性類的可訪問性有兩個級別:public和internal。標記為public的類可以被系統(tǒng)內(nèi)任何程序集中的代碼訪問。標記為internal的類只能被它自己所在的程序集內(nèi)的類看到。internal是類的默認可訪問級別,所以,只有在類的聲明中顯式地指定修飾符public,程序集外部的代碼才能訪問該類??梢允褂胕nternal訪問修飾符顯式地聲明一個類為內(nèi)部的。4.5訪問修飾符 4.5.2類中各成員的可訪問性成員(數(shù)據(jù)成員和方法成員)的可訪問性描述了類成員的可見性。聲明在類中的每個成員對系統(tǒng)的不同部分可見,這依賴于類聲明中指派給它的訪問修飾符。有7個成員訪問級別:公有的(public)私有的(private)受保護的(protected)內(nèi)部的(internal)受保護內(nèi)部的(protectedinternal)4.5訪問修飾符 在類體中,必須對每個成員指定成員的訪問級別。如果不指定某個成員的訪問級別,它的隱式訪問級別為private。成員不能比它的類更可訪問。也就是說,如果一個類的可訪問性限于它所在的程序集,那么類的成員個體也不能從程序集的外部看到,無論它們的訪問修飾符是什么。1、公有成員的可訪問性public訪問級別是限制性最少的。所有的類,包括程序集內(nèi)部的類和外部的類都可以自由地訪問成員。4.5訪問修飾符 2、私有成員的可訪問性私有成員的可訪問性限制是最嚴格的。private類成員只能被它自己的類的成員訪問。它不能被其他的類訪問,包括繼承它的類。然而,private成員能被嵌套在它的類中的成員訪問。例4-5:類中成員的可訪問性4.5訪問修飾符 namespacech4_5{classStudent{privatestring_name;//姓名
publicintAge;//年齡publicstringIdNumber;//身份證號}
classProgram{staticvoidMain(string[]args){Studentobj=newStudent();//obj._name="張三";//無法訪問編譯錯誤obj.Age=20;//可以訪問}}}4.5訪問修飾符 3、受保護成員的可訪問性:protected訪問級別如同private訪問級別,除了一點,它允許派生自該類的類訪問該成員。例4-6類中protected修飾符的可訪問性4.5訪問修飾符 namespacech4_6{classPoint{protectedintx;protectedinty;}classDerivedPoint:Point{}
classProgram{staticvoidMain(){DerivedPointdp=newDerivedPoint();//dp.x=10;dp.y=15;//此處不是在派生類中,不能訪問基類中protected修飾的成員//Console.WriteLine("x={0},y={1}",dp.x,dp.y);Pointp=newPoint();//p.x=20;//此處出錯,因為x是protected類型,只有在派生類中才可使用。}}}4.5訪問修飾符 例4-7類中protected修飾符的可訪問性namespacech4_7{classPoint{protectedintx;protectedinty;}classDerivedPoint:Point{
staticvoidMain(){DerivedPointdp=newDerivedPoint();//在派生類中直接訪問基類中protected修飾的成員dp.x=10;dp.y=15;Console.WriteLine("x={0},y={1}",dp.x,dp.y);}}}4.5訪問修飾符 4、內(nèi)部成員的可訪問性:標記為internal的成員對程序集內(nèi)部的所有類可見,但對程序集外部的類不可見。Internal關鍵字舉例:Internal關鍵字只有在同一程序集的文件中才是可訪問的。1)創(chuàng)建一個類庫項目,編譯為BaseClass.dll,新建類庫,BaseClassnamespaceBaseClass{publicclassMyClass{internalintintM=0;}}4.5訪問修飾符 2)新建一個項目InternalTest在右邊添加引用,通過瀏覽找到BaseClass.dll在代碼上方加上引用,usingBaseClass;4.5訪問修飾符 usingBaseClass;
namespaceTestInternal{classProgram{staticvoidMain(string[]args){MyClassmc=newMyClass();M=50;//此處出現(xiàn)錯誤,因為MyClass中的intM成員的訪問修飾符是internal,只能在同一命名空間底下訪問。}}}4.5訪問修飾符 3)創(chuàng)建一個新的類庫項目,編譯為BaseClassPublic.dll,新建類庫,BaseClassPublicnamespaceBaseClassPublic{publicclassMyClass{publicintintM=0;}}4.5訪問修飾符 4)在項目InternalTest,在右邊添加引用,通過瀏覽找到BaseClassPublic.dll,在代碼上方加上引用,usingBaseClassPublic;usingBaseClassPublic;namespaceTestInternal{classProgram{staticvoidMain(string[]args){MyClassmc=newMyClass();M=50;//此處不再出現(xiàn)錯誤,因為MyClass中的intM成員的訪問修飾符是public,雖然不在同一命名空間底下,但是也可以訪問。}}}4.5訪問修飾符 5、受保護內(nèi)部成員的可訪問性:標記為protectedinternal的成員對所有繼承該類的類以及所有程序集內(nèi)部的類可見。4.5訪問修飾符 4.6類的多態(tài) 多態(tài)性(polymorphism)是面向對象程序設計中的一個重要概念,它是指同一個消息被不同類型的對象接收時產(chǎn)生不同的行為。所謂消息是指對類成員的調用,不同的行為是指調用了不同的類成員。4.6.1方法的重載方法重載(functionoverload)是指功能相似,方法名相同但所帶參數(shù)不同或返回值類型不同的一組方法。這里的“所帶參數(shù)不同”既可能是參數(shù)的數(shù)據(jù)類型不同也可能是參數(shù)的個數(shù)不同。前面我們已經(jīng)介紹了方法的重載。雖然方法的名字都相同,可是不同的方法對應不同的處理。4.6類的多態(tài) 4.6.2成員的隱藏類的繼承中,派生類繼承了基類的所有成員,但在實際編程中,有時我們需要子類擁有和父類同名、參數(shù)一致但完成功能不同的方法,從而屏蔽掉父類的方法,我們稱這種情況為成員隱藏。成員隱藏使用關鍵字new。在派生類中用new關鍵字聲明與基類同名的方法,格式如下:
訪問修飾符new類型成員名;此格式中的成員可以是字段、屬性、方法等,當然,若為方法,則相應的也應該有方法體。比如若基類中有一方法:publicvoidF(){…}則在派生類中重寫該方法應該為:publicnewvoidF(){…}。4.6類的多態(tài) 例4-8:用new隱藏基類的字段namespacech4_8{publicclassMyBase{publicstaticintx=55;publicstaticinty=22;}publicclassMyDerived:MyBase{newpublicstaticintx=100;//利用new隱藏基類的x
publicstaticvoidMain(){//打印x:Console.WriteLine(x);//訪問隱藏基類的x:Console.WriteLine(MyBase.x);//打印不隱藏的y:Console.WriteLine(y);Console.ReadKey();}}}輸出結果為:10055224.6類的多態(tài) 例4-9:隱藏基類的方法namespacech4_9{publicclassMyBase{publicintx;publicvoidMyVoke(){Console.WriteLine("thisistheMyBase!");}}//在派生類中用MyVoke名稱聲明成員會隱藏基類中的MyVoke方法,即:
publicclassMyDerived:MyBase{newpublicvoidMyVoke(){Console.WriteLine("thisistheMyDerived!");}
}
publicclassProgram{publicstaticvoidMain(){MyDerivedm=newMyDerived();m.MyVoke();Console.ReadKey();}}}輸出結果為:thisistheMyDerived!4.6類的多態(tài) 4.6類的多態(tài) 4.6.3虛方法當子類需要重寫父類方法的時候,就需要父類的方法是虛方法,當有多個子類重寫了父類方法就有多種實現(xiàn),從而現(xiàn)實了多態(tài)。比如,有個作為父類的Person類中用于問好的方法為Hello,輸出“你好”,現(xiàn)在有兩個子類分別是Student和Teacher(假設他們必須這樣說)那Student問好就該說,老師好而Teacher問好就該說,同學好,所以就需要重寫了。classPerson{publicvirtualvoidHello(){Console.WriteLine("你好");}}classStudent:Person{publicoverridevoidHello(){Console.WriteLine("老師好");}}classTeacher:Person{publicoverridevoidHello(){Console.WriteLine("同學好");}}4.6類的多態(tài) 虛方法在基類中的聲明格式:publicvirtual方法名稱(參數(shù)列表){方法體}在派生類中的聲明格式:publicoverride方法名稱(參數(shù)列表){方法體}其中基類與派生類中的方法名稱與參數(shù)列必須完全一致。當類中的方法聲明前加上了virtual修飾符,我們稱此方法為虛方法,反之為非虛方法,使用了virtual修飾符后不允許再有static,abstract或override修飾符,對于非虛的方法無論被其所在類的實例調用還是被這個類的派生類的實例調用,方法的執(zhí)行方式不變,而對于虛方法,它的執(zhí)行方式可以被派生類改變,這種改變是通過方法的重載來實現(xiàn)的。4.6類的多態(tài) 例4-10:虛方法namespacech4_10{classMyBase{publicvoidF(){Console.WriteLine("MyBase.F");}publicvirtualvoidG(){Console.WriteLine("MyBase.G");}}
4.6類的多態(tài) classMyDerived:MyBase{newpublicvoidF(){Console.WriteLine("MyDerived.F");}publicoverridevoidG(){Console.WriteLine("MyDerived.G");}}
4.6類的多態(tài) classProgram{staticvoidMain(){MyDerivedb=newMyDerived();MyBasea=b;a.F();b.F();a.G();b.G();Console.ReadKey();}}}輸出結果:MyBase.FMyDerived.FMyDerived.GMyDerived.G4.6類的多態(tài) 4.6.4base關鍵字
前面說明了如何利用多態(tài)的特性在子類中重載基類方法,來完全替換基類中的功能。不過這有點極端——有時重寫方法是為了擴展基本功能,而不是替代原來的功能。
為此,需要像上面那樣使用override關鍵字重載方法,但是在新的實現(xiàn)代碼中,仍然調用方法的原始實現(xiàn)代碼。這樣就可以在調用原始實現(xiàn)代碼的前后添加自己的代碼——即在擴展功能的同時,仍利用基類中的代碼。為了直接從基類中調用方法,可以使用base關鍵字。這個關鍵字可以在任何類中使用,它提供了基類中的所有方法,以供使用。例4-11:使用base關鍵字擴展基本功能4.6類的多態(tài) namespacech4_11{publicclassPerson{protectedstringstrid="42280101010111";protectedstringstrname="張三";publicvirtualvoidGetInfo(){Console.WriteLine("姓名:{0}",strname);Console.WriteLine("身份證號:{0}",strid);}}
4.6類的多態(tài) classStudent:Person{publicstringsno="1308001";publicoverridevoidGetInfo(){//調用基類的GetInfo方法:base.GetInfo();Console.WriteLine("學號:{0}",sno);}}4.6類的多態(tài) classProgram{publicstaticvoidMain(){Students=newStudent();s.GetInfo();Console.ReadKey();}}}4.6類的多態(tài) 4.7密封類 前面,我們講了類的繼承,想想看如果所有的類都可以被繼承,濫用繼承會帶來什么后果,類的層次結構體系將變得十分龐大,類之間的關系雜亂無章,對類的理解和使用都會變得十分困難,有時候我們并不希望自己編寫的類被繼承,另一些時候有的類已經(jīng)沒有再被繼承的必要,所以C#提出了一個密封類的概念幫助開發(fā)人員來解決這一問題。密封類在聲明中使用sealed修飾符,這樣就可以防止該類被其它類繼承。例4-12密封類namespacech4_12{abstractclassA{publicabstractvoidF();}sealedclassB:A{publicoverridevoidF(){//F的具體實現(xiàn)代碼}}
4.7密封類 classProgram{staticvoidMain(string[]args){}}}如果我們嘗試寫下面的代碼classC:B{}C#會指出這個錯誤,告訴你B是一個密封類不能試圖從B中派生任何類。密封方法的概念,以防止方法所在類的派生類中對該方法的重載,對方法可以使用sealed修飾符,這時我們稱該方法是一個密封方法。不是類的每個成員方法都可以作為密封方法,密封方法必須是對基類的虛方法進行重載,提供具體的實現(xiàn)方法,所以在方法的聲明中sealed修飾符總是和override修飾符同時使用。4.7密封類 例4-13:密封方法namespacech4_13{classA{publicvirtualvoidF(){Console.WriteLine("A.F");}publicvirtualvoidG(){Console.WriteLine("A.G");}}4.7密封類 classB:A{sealedoverridepublicvoidF(){Console.WriteLine("B.F");}overridepublicvoidG(){Console.WriteLine("B.G");}}
4.7密封類 classC:B{overridepublicvoidG(){Console.WriteLine("C.G");}}classProgram{staticvoidMain(string[]args){}}}4.7密封類 分析:類B對基類A中的兩個虛方法均進行了重載,其中F方法使用了sealed修飾符成為一個密封方法,G方法不是密封方法,所以在B的派生類C中可以重載方法G,但不能重載方法F。4.7密封類 4.8抽象類在面向對象的概念中,所有的對象都是通過類來描繪的,但是反過來,并不是所有的類都是用來描繪對象的,如果一個類中沒有包含足夠的信息來描繪一個具體的對象,這樣的類就是抽象類。抽象類往往用來表征對問題領域進行分析、設計中得出的抽象概念,是對一系列看上去不同,但是本質上相同的具體概念的抽象。比如,在一個圖形編輯軟件的分析設計過程中,就會發(fā)現(xiàn)問題領域存在著圓、三角形這樣一些具體概念,它們是不同的,但是它們又都屬于形狀這樣一個概念,形狀這個概念在問題領域并不是直接存在的,它就是一個抽象概念。而正是因為抽象的概念在問題領域沒有對應的具體概念,所以用以表征抽象概念的抽象類是不能夠實例化的。C#中的抽象類具有以下特性:1、抽象類不能實例化。2、抽象類可以包含抽象方法和抽象訪問器。3、不能用sealed修飾符修飾抽象類,因為這兩個修飾符的含義是相反的。采用sealed修飾符的類無法繼承,而abstract修飾符要求對類進行繼承。4、從抽象類派生的非抽象類必須包括繼承的所有抽象方法和抽象訪問器的實際實現(xiàn)。5、抽象類是指基類的定義中聲明不包含實現(xiàn)代碼的方法,實際上就是一個不具有任何具體功能的方法,這樣的方法唯一作用就是讓派生類重寫。6、在基類定義中只要類體中包含一個抽象方法,該類即為抽象類,在抽象類中也可以聲明一般的虛方法。4.8抽象類聲明抽象類與抽象方法均使用關鍵字abstract,其基本格式為:publicabstract類名{ publicabstract返回類型方法名稱(參數(shù)列表); …}抽象方法聲明時沒有方法體,只有方法簽名,后跟一個分號。重寫抽象方法的格式為:publicoverride返回類型方法名稱(參數(shù)列表){方法體}其中方法名稱和參數(shù)列表必須與抽象類中的抽象方法完全一致。4.8抽象類例4-14:抽象類與抽象方法的定義與重寫namespacech4_14{///定義抽象類
abstractpublicclassAnimal{//定義字段
protectedint_id;//定義屬性,在抽象方法聲明中不能使用static或virtual修飾符4.8抽象類publicabstractintId{get;set;}//定義方法
publicabstractvoidEat();}///實現(xiàn)抽象類
publicclassDog:Animal{
4.8抽象類publicoverrideintId{get{return_id;}set{_id=value;}}
publicoverridevoidEat(){Console.WriteLine("DogEats.");}}classProgram{staticvoidMain(string[]args){}}}4.8抽象類在面向對象方法中,抽象類主要用來進行類型隱藏。構造出一個固定的一組行為的抽象描述,但是這組行為卻能夠有任意個可能的具體實現(xiàn)方式。這個抽象描述就是抽象類,而這一組任意個可能的具體實現(xiàn)則表現(xiàn)為所有可能的派生類。模塊可以操作一個抽象體。由于模塊依賴于一個固定的抽象體,因此它可以是不允許修改的;同時,通過從這個抽象體派生,也可擴展此模塊的行為功能。為了能夠實現(xiàn)面向對象設計的一個最核心的原則OCP(Open-ClosedPrinciple),抽象類是其中的關鍵所在。4.8抽象類4.9接口在軟件開發(fā)過程中,有時我們編寫的程序需要提供給外部商家進行二次開發(fā)或者其它的服務,但我們又不希望他們看見我們程序的內(nèi)部細節(jié),在此情況下,我們可以把我們的產(chǎn)品做成組件,用接口描述組件對外提供的服務。組件和組件之間、組件和客戶之間都通過接口進行交互,所以接口在軟件設計過程中還是一個很重要的知識。接口用來定義一種程序的協(xié)定。實現(xiàn)接口的類與接口的定義嚴格一致。接口可以包含方法、屬性、事件和索引器。接口不可以包括字段,接口本身不提供它所定義的成員的實現(xiàn)。接口只指定實現(xiàn)該接口的類或接口必須提供的成員。所以接口不能被實例。定義接口使用的關鍵字為interface,其一般形式為:[修飾符]interface接口名稱[:基接口列表]{
接口體成員列表}其中,允許使用的修飾符有:public、protected、internal、private。修飾符定義了對接口的訪問權限。
C#中類的繼承只可以是一個,即子類只能派生于一個父類,而有時你必須繼承多個類的特性,為了實現(xiàn)多重繼承必須使用接口技術,下面是對接口的多重繼承進行介紹。4.9接口例4-15:對接口的多重繼承。namespacech4_15{//定義一個描述點的接口interfaceIPoint{intx{get;set;}
4.9接口inty{get;set;}}interfaceIPoint2{inty{get;set;}}
4.9接口//在point中繼承了兩個父類接口,并分別使用了兩個父類接口的方法
classPoint:IPoint,IPoint2{//定義兩個類內(nèi)部訪問的私有成員變量privateintpX;privateintpY;publicPoint(intx,inty){pX=x;pY=y;}
4.9接口//定義的屬性,IPoint接口方法實現(xiàn)publicintx{get{returnpX;}set{pX=value;}}//IPoint1接口方法實現(xiàn)
publicinty{get{returnpY;}set{pY=value;}}}4.9接口classProgram{privatestaticvoidOutPut(IPointp){Console.WriteLine("x={0},y={1}",p.x,p.y);}publicstaticvoidMain(){Pointp=newPoint(15,30);Console.Write("TheNewPointis:");OutPut(p);stringmyName=Console.ReadLine();Console.Write("mynameis{0}",myName);}}}4.9接口1.接口用于描述一組類的公共方法/公共屬性。它不實現(xiàn)任何的方法或屬性,只是告訴繼承它的類至少要實現(xiàn)哪些功能,繼承它的類可以增加自己的方法。2.使用接口可以使繼承它的類命名統(tǒng)一/規(guī)范,易于維護。比如:兩個類“狗”和“貓”,如果它們都繼承了接口“動物”,其中動物里面有個方法Behavior(),那么狗和貓必須得實現(xiàn)Behavior()方法,并且都命名為Behavior這樣就不會出現(xiàn)命名太雜亂的現(xiàn)象。如果命名不是Behavior(),接口會約束即不按接口約束命名編譯不會通過。4.9接口例4-16:接口的使用namespacech4_16{//公共接口:"動物"publicinterfaceIAnimal{voidBehavior();//行為方法,描述各種動物的特性
}//類:狗
publicclassDog:IAnimal{stringActiveTime="白天";
4.9接口publicvoidBehavior(){Console.Write("我晚上睡覺,白天活動");}}//類:貓
publicclassCat:IAnimal{stringActiveTime="夜晚";publicvoidBehavior(){Console.Write("我白天睡覺,晚上活動");}}4.9接口//簡單的應用:publicclassProgram{publicstaticvoidMain(){DogmyDog=newDog();myDog.Behavior();//輸出:"我晚上睡覺,白天活動"CatmyCat=newCat();myCat.Behavior();//輸出:"我白天睡覺,晚上活動"Console.ReadKey();}}}4.9接口以上調用不同的類的相同名方法,會輸出不同的內(nèi)容,也就是說每個類里面的同名方法完成的功能可以是完全不同的。更進一步,不是用上面Main方法這樣一個一個調用類的方法,用多態(tài)性實現(xiàn)其調用。4.9接口例4-17:用多態(tài)性實現(xiàn)調用namespacech4_17{//公共接口:"動物"publicinterfaceIAnimal{voidBehavior();//行為方法,描述各種動物的特性
}//類:狗
publicclassDog:IAnimal{stringActiveTime="白天";
4.9接口publicvoidBehavior(){Console.WriteLine("我晚上睡覺,白天活動");}}//類:貓
publicclassCat:IAnimal{stringActiveTime="夜晚";publicvoidBehavior(){Console.WriteLine("我白天睡覺,晚上活動");}}
4.9接口//簡單的應用:publicclassProgram{staticvoidBehavior(IAnimalmyIanimal){myIanimal.Behavior();}publicstaticvoidMain(){DogmyDog=newDog();Behavior(myDog);//輸出:"我晚上睡覺,白天活動"CatmyCat=newCat();Behavior(myCat);//輸出:"我白天睡覺,晚上活動"Console.ReadKey();}}}4.9接口3.提供永遠的接口。當類增加時,現(xiàn)有接口方法能夠滿足繼承類中的大多數(shù)方法,沒必要重新給新類設計一組方法,也節(jié)省了代碼,提高了開發(fā)效率。例4-18:再增加一個“龜”類:4.9接口namespacech4_18{//公共接口:"動物"publicinterfaceIAnimal{voidBehavior();//行為方法,描述各種動物的特性
}//類:狗
publicclassDog:IAnimal{stringActiveTime="白天";
4.9接口publicvoidBehavior(){Console.WriteLine("我晚上睡覺,白天活動");}}//類:貓
publicclassCat:IAnimal{stringActiveTime="夜晚";publicvoidBehavior(){Console.WriteLine("我白天睡覺,晚上活動");}}
4.9接口//類:龜
publicclassTortoise:IAnimal{stringActiveTime="很難說";publicvoidBehavior(){Console.WriteLine("我可以不活動,一睡就睡五千年!");}}
//簡單的應用:
4.9接口publicclassProgram{staticvoidBehavior(IAnimalmyIanimal){myIanimal.Behavior();}publicstaticvoidMain(){DogmyDog=newDog();Behavior(myDog);//輸出:"我晚上睡覺,白天活動"CatmyCat=newCat();Behavior(myCat);//輸出:"我白天睡覺,晚上活動"
4.9接口TortoisemyTortoise=newTortoise();Behavior(myTortoise);//輸出:"我白天睡覺,晚上活動"Console.ReadKey();}}}4.9接口那么也可以調用上面多態(tài)方法,所以說接口使方法具有較好擴展性。抽象類與接口緊密相關。然而接口又比抽象類更抽象,這主要體現(xiàn)在它們的差別上:抽象類表示該類中可能已經(jīng)有一些方法的具體定義,但是接口就僅僅只能定義各個方法的界面(方法名,參數(shù)列表,返回類型),并不關心具體細節(jié)。
類可以實現(xiàn)無限個接口,但僅能從一個抽象(或任何其他類型)類繼承,從抽象類派生的類仍可實現(xiàn)接口,從而得出接口是用來解決多重繼承問題的。
抽象類當中可以存在非抽象的方法,可接口不能,且它里面的方法只是一個聲明必須用public來修飾沒有具體實現(xiàn)的方法。
4.9接口抽象類中的成員變量可以被不同的修飾符來修飾,可接口中的成員變量默認的都是靜態(tài)常量(staticfinal)。4.9接口抽象類是對象的抽象,然而接口是一種行為規(guī)范。抽象類里面可以有非抽象方法但接口里只能有抽象方法聲明方法的存在而不去實現(xiàn)它的類被叫做抽象類(abstractclass),它用于要創(chuàng)建一個體現(xiàn)某些基本行為的類,并為該類聲明方法,但不能在該類中實現(xiàn)該類的情況。不能創(chuàng)建abstract類的實例。然而可以創(chuàng)建一個變量,其類型是一個抽象類,并讓它指向具體子類的一個實例。不能有抽象構造函數(shù)或抽象靜態(tài)方法。Abstract類的子類為它們父類中的所有抽象方法提供實現(xiàn),否則它們也是抽象類為。取而代之,在子類中實現(xiàn)該方法。知道其行為的其它類可以在類中實現(xiàn)這些方法。接口(interface)是抽象類的變體。在接口中,所有方法都是抽象的。多繼承性可通過實現(xiàn)這樣的接口而獲得。接口中的所有方法都是抽象的,沒有一個有程序體。4.9接口4.10委托與事件4.10.1委托委托是C#中的一種引用類型,主要用于.NETFramework中的事件處理程序和回調函數(shù)。一個委托可以看作一個特殊的類,因而它的定義可以像常規(guī)類一樣放在同樣的位置。與其他類一樣,委托必須先定義以后,再實例化。委托派生于基類System.Delegate,不過委托的定義和常規(guī)類的定義方法不太一樣。委托的定義通過關鍵字delegate來定義:如:publicdelegateintmyDelegate(intx,inty);代碼定義了一個新委托,它可以封裝任何返回為int,帶有兩個int類型參數(shù)的方法。
該委托能夠代表那些返回值為int輸入?yún)?shù)為2個int的方法。4.10委托與事件如下面的2個方法:publicintsub(intx,inty){returnx+y;}publicintfub(intx,inty){returnx-y;}可通過以下步驟使用定義的委托
步驟1:定義方法publicintsub(intx,inty){returnx+y;}
步驟2:實例委托實例myDelegatecal=newmyDelegate(sub);4.10委托與事件步驟3:可以直接使用cal調用sub方法cal(10,3);
用cal調用與直接調用sub方法是等價的;cal(10,3);等價于sub(10,3);委托可以使用+運算符號將多個委托組合在一起,或使用–運算符號從組合委托中減去一個委托。4.10委托與事件例4-19:委托舉例namespacech4_19{//定義委托publicdelegateintmyDelegate(intx,inty);
classMyClass{publicintfub(intx,inty){Console.WriteLine(x-y);returnx-y;}publicintsub(intx,inty){Console.WriteLine(x+y);returnx+y;}}classProgram{staticvoidMain(string[]args){MyClassmc=newMyClass();myDelegatemyd=newmyDelegate(mc.fub);//再定義一個委托實例4.10委托與事件// myd(10,3);//利用委托實例調用fub方法myDelegatecal=newmyDelegate(mc.sub); myDelegatezong=cal+myd;//定義委托 zong(10,3);//此時再調用Console.ReadKey();}}}
此時輸出: 13 74.10委托與事件4.10委托與事件例4-20:委托舉例namespacech4_20{//聲明一個委托MyDelegatepublicdelegatevoidMyDelegate(stringstr);
publicclassC{publicstaticvoidM1(stringstr){Console.WriteLine("From:C.M1:{0}",str);}
publicstaticvoidM2(stringstr){Console.WriteLine("From:C.M2:{0}",str);}
publicvoidM3(stringstr){Console.WriteLine("From:C.M3:{0}",str);}}
publicclassC1{publicstaticvoidP1(stringstr){Console.WriteLine("From:C1.P1:{0}",str);}}
4.10委托與事件publicclassC2{publicvoidP1(stringstr){Console.WriteLine("From:C2.P1:{0}",str);}}classProgram{
4.10委托與事件staticvoidMain(string[]args){//創(chuàng)建一個委托實例,封裝C類的靜態(tài)方法M1MyDelegated1=newMyDelegate(C.M1);d1("D1");//M1
//創(chuàng)建一個委托實例,封裝C類的靜態(tài)方法M2MyDelegated2=newMyDelegate(C.M2);d2("D2");//M2
//創(chuàng)建一個委托實例,封裝C類的實例方法M3MyDelegated3=newMyDelegate(
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經(jīng)權益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025年廣安市武勝縣公證處招聘非在編公證員助理的備考題庫及答案詳解參考
- 初中歷史人物評價學習分析結果的可視化呈現(xiàn)與教學策略改進研究教學研究課題報告
- 2025年湖州市敬業(yè)特種設備技術咨詢有限公司招聘5人備考題庫及答案詳解一套
- 3D打印導板在神經(jīng)外科手術中的精準設計與規(guī)劃
- 2025年天津市政建設集團有限公司面向社會公開選聘總法律顧問備考題庫及參考答案詳解一套
- 2025年關于公開招聘派遣至莆田市城廂區(qū)交通運輸局非在編工作人員的備考題庫及參考答案詳解1套
- 平?jīng)鍪惺兄睂W校公開招聘2026屆協(xié)議培養(yǎng)師范生23人備考題庫(第二批)及答案詳解1套
- 2025年非遺皮影五年文旅演出效果報告
- 2025年中國藥科大學研究生院工作人員招聘備考題庫及參考答案詳解一套
- 2025年西安市浐灞第一幼兒園招聘備考題庫附答案詳解
- 2025-2026學年人教版八年級上學期期末測試卷英語(含答案及聽力原文無音頻)
- 托福真題試卷(含答案)(2025年)
- 2025年廣東省第一次普通高中學業(yè)水平合格性考試(春季高考)語文試題(含答案詳解)
- 2026廣東深圳市檢察機關招聘警務輔助人員13人筆試考試備考試題及答案解析
- 雨課堂學堂在線學堂云《金融風險管理:量化投資視角( 暨南)》單元測試考核答案
- 臨床試驗盲法方案設計的法規(guī)符合性優(yōu)化
- 留聲機美術課件
- 2026屆廣東深圳市高一生物第一學期期末監(jiān)測試題含解析
- 直播基地的管理制度
- 拍賣公司計劃書
- 水滸傳課件講宋江
評論
0/150
提交評論