第4講-面向對象的程序設計_第1頁
第4講-面向對象的程序設計_第2頁
第4講-面向對象的程序設計_第3頁
第4講-面向對象的程序設計_第4頁
第4講-面向對象的程序設計_第5頁
已閱讀5頁,還剩78頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

VisualC#.NET程序設計第四講VisualC#.NET面向對象程序設計沈志忠zzshen78@163.com北京科技大學信息工程學院第7章

面向對象的程序設計

本章要點:

面向對象的基本概念

類的定義與對象的聲明

構造函數(shù)和析構函數(shù)

類的靜態(tài)成員和實例成員

方法重載及運算符重載的編程實現(xiàn)

類的繼承與多態(tài)性的編程實現(xiàn)

類的屬性的實現(xiàn)7.1循序漸進學理論

7.1.1面向對象程序設計概述

1.面向對象程序設計的由來面向對象的程序設計是一種基于結構分析的、以數(shù)據(jù)為中心的程序設計方法。面向對象的程序設計方法總體思路是:將數(shù)據(jù)及處理這些數(shù)據(jù)的操作都封裝(Encapsulation)到一個稱為類(Class)的數(shù)據(jù)結構中,在程序中使用的是類的實例——對象。對象是代碼與數(shù)據(jù)的集合,是封裝好了的一個整體,對象具有一定的功能。也就是說對象是具有一定功能的程序實體。程序是由一個個對象構成的,對象之間通過一定的“相互操作”傳遞消息,在消息的作用下,完成特定的功能。

2.面向對象程序設計的基本概念

(1)類和對象通常把具有同樣性質和功能的東西所構成的集合叫作類。

(2)屬性、方法與事件屬性是對象的狀態(tài)和特點。

方法是對象能夠執(zhí)行的一些操作,它體現(xiàn)了對象的功能。事件是對象能夠識別和響應的某些操作。(3)封裝

所謂的封裝,就是將用來描述客觀事物的一組數(shù)據(jù)和操作組裝在一起,形成一個類。

(4)繼承類之間除了有相互交流或訪問的關系以外,還可能存在著一種特殊的關系,這就是繼承。在VisualC#中只支持單繼承,即一個派生類只能有一個基類。(5)重載重載指的是方法名稱一樣,但如果參數(shù)不同,就會有不同的具體實現(xiàn)。重載主要有兩類:方法重載及運算符重載。

(6)多態(tài)性

所謂多態(tài)性就是在程序運行時,面向對象的語言會自動判斷對象的派生類型,并調用相應的方法。7.1.2類和對象的聲明

1.類的聲明[格式]:class類名[:基類類名] {

成員定義列表;

}【例7-1】定義一個Student類,用來對學生的信息和功能進行描述。假設學生具有學號、姓名、年齡、性別、平均成績等特征,并且具有設置學生特征和顯示學生特征的功能。2.對象的聲明

[格式]:類名 實例名=new類名([參數(shù)]);3.類的成員(1)類成員的分類

類的具體成員如下。

常量:用來定義與類相關的常量值。

域(字段):類中的變量,相當于C++中的成員變量。

方法:完成類中各種計算或功能的操作。

屬性:定義類的特征,并對它們提供讀、寫操作。

事件:由類產生的通知,用于說明發(fā)生了什么事情。

索引器:允許編程人員在訪問數(shù)組時,通過索引器訪問類的多個實例。又稱下標指示器。

運算符:定義類的實例能使用的運算符。

構造函數(shù):在類被實例化時首先執(zhí)行的函數(shù),主要是完成對象初始化操作。

析構函數(shù):在對象被銷毀之前最后執(zhí)行的函數(shù),主要是完成對象結束時的收尾操作。類成員的可訪問性

在編寫程序時,可以對類的成員使用不同的訪問修飾符,從而定義它們的訪問級別,即類成員的可訪問性(Accessibility)。publicprivateprotectedinternalinternalprotectednew

(1)公共成員它通過在成員聲明中加public修飾符來定義。“公共的”直覺意義是“無限制訪問”,定義的成員可以在類的外部進行訪問。(2)保護成員 保護成員通過在成員聲明中使用protected修飾符來定義。為了方便派生類的訪問,但又不希望其他無關類隨意訪問,這時就可以使用protected修飾符,將成員聲明為保護的。(3)私有成員 私有成員通過在成員聲明中使用private修飾符來定義。C#中的私有成員只有類中的成員可以訪問,在類的外部是禁止直接訪問私有成員的。這也是C#中成員聲明的默認方式,即若在成員聲明時沒有使用任何訪問修飾符,那么C#自動將它限定為私有成員。(4)內部成員 內部成員通過在成員聲明中使用internal修飾符來定義。該成員只能被程序集中的代碼訪問,而程序集之外的代碼無法訪問。(5)保護內部成員 同一個程序集中的所有類,以及所有程序集中的子類都可以訪問。(6)new

new關鍵字可以在派生類中隱藏基類的方法,也就說在使用派生類的方法是調用的方法是New關鍵字新定義出來的方法,而不是基類的方法。namespaceExample05Lib

{

publicclassClass1

{

internalStringstrInternal=null;

publicStringstrPublic;

internalprotectedStringstrInternalProtected=null;

}

}

Example05Lib項目的Class2類可以訪問到Class1的strInternal成員,當然也可以訪問到strInternalProtected成員,因為他們在同一個程序集里

Example05項目里的Class3類無法訪問到Class1的strInternal成員,因為它們不在同一個程序集里。但卻可以訪問到strInternalProtected成員,因為Class3是Class1的繼承類publicclassBaseC{publicintx;publicvoidInvoke(){}}publicclassDerivedC:BaseC{newpublicvoidInvoke(){}}

類的成員又可以分成靜態(tài)成員和非靜態(tài)成員。在聲明成員時,如果在語句前加上static保留字,則該成員是靜態(tài)成員,如果沒有static保留字,則成員是非靜態(tài)成員。二者最重要的區(qū)別是:靜態(tài)成員屬于類所有,非靜態(tài)成員屬于類的實例所有,所以又稱實例成員。

類的靜態(tài)成員和實例成員7.1.3類的構造函數(shù)和析構函數(shù)

1.構造函數(shù)構造函數(shù)主要用來為對象分配存儲空間,完成初始化操作(如給類的成員變量賦值等)。在C#中,類的構造函數(shù)遵循以下規(guī)定。(1)構造函數(shù)的函數(shù)名和類的名稱一樣。(2)當某個類沒有構造函數(shù)時,系統(tǒng)將自動為其創(chuàng)建構造函數(shù),這種構造函數(shù)稱為默認構造函數(shù)。如例7-2中默認的構造函數(shù)為:

Example1(){};

(3)構造函數(shù)的訪問修飾符總是public。如果是private,則表示這個類不能被實例化,這通常用于只含有靜態(tài)成員的類中。(4)構造函數(shù)由于不需要顯式調用,因而不用聲明返回類型。(5)構造函數(shù)可以帶參數(shù)也可以不帶參數(shù)。

2.析構函數(shù)析構函數(shù)在對象銷毀時被調用,常用來釋放對象占用的存儲空間。析構函數(shù)具有以下特點。(1)析構函數(shù)不能帶有參數(shù)。(2)析構函數(shù)不能擁有訪問修飾符。

(3)不能顯式地調用析構函數(shù)。(4)析構函數(shù)的命名規(guī)則是在類名前加上一個“~”號。如上例的Example1類的析構函數(shù)為:

~Example1(){};(5)析構函數(shù)在對象銷毀時自動調用?!纠?-3】類的構造函數(shù)和析構函數(shù)的演示。(程序代碼詳見例7-3)[執(zhí)行結果]

usingSystem;classExam{staticpublicinta;//靜態(tài)成員

publicintb;//實例成員

publicExam()//構造函數(shù),沒有參數(shù),用來給成員變量賦初值0{a=0;b=0;}publicExam(intm,intn)//構造函數(shù),有參數(shù),用來給成員變量賦特定的初值

{a=m;b=n;}~Exam()//析構函數(shù)

{}}classA_7_3{publicstaticvoidMain(){ExamE1=newExam();//產生類的實例E1,自動調用無參數(shù)的構造函數(shù)

Console.WriteLine("a={0},b={1}",Exam.a,E1.b);ExamE2=newExam(10,20);//產生類的實例E2,自動調用有參數(shù)的構造函數(shù)

Console.WriteLine("a={0},b={1}",Exam.a,E2.b);}}7.1.4類的方法及方法的重載

1.方法的定義

[格式]:[方法修飾符]返回值類型方法名([參數(shù)列表]){方法實現(xiàn)部分;}2.靜態(tài)方法和非靜態(tài)方法對于靜態(tài)方法和非靜態(tài)方法,只需抓住以下幾點:(1)靜態(tài)方法屬于類所有,非靜態(tài)方法屬于類定義的對象所有;(2)非靜態(tài)方法可以訪問類中包括靜態(tài)成員在內的所有成員,而靜態(tài)方法只能訪問類中的靜態(tài)成員?!纠?-4】靜態(tài)方法和動態(tài)方法的演示。請觀察并分析下列程序的執(zhí)行結果。(程序代碼詳見例7-4)[執(zhí)行結果]

3.方法的參數(shù)(1).值參數(shù)(沒有修飾符)當使用值類型的參數(shù)調用方法時,編譯程序將實參的值做一份副本,并且把此副本傳遞給該方法的相應形參。被調用的方法不會修改內存中實參的值,所以使用值參數(shù)時,可以保證實參值是安全的。定義含有值類型參數(shù)方法的格式:

[修飾符]返回的數(shù)據(jù)類型方法名(參數(shù)列表)方法的參數(shù)【例】下面的程序演示了當方法Sort傳遞的是值參數(shù)時,對形參的修改不影響其實參。usingSystem;classMyclass{publicvoidSort(intx,inty,intz) { inttmp;//tmp是方法Sort的局部變量

//將x,y,z按從小到大排序

if(x>y){tmp=x;x=y;y=tmp;} if(x>z){tmp=x;x=z;z=tmp;} if(y>z){tmp=y;y=z;z=tmp;} }}classTest{staticvoidMain(){ Myclassm=newMyclass(); inta,b,c; a=30;b=20;c=10; m.Sort(a,b,c); Console.WriteLine("a={0},b={1},c={2}",a,b,c); Console.Read();}}運行結果如圖3.13所示:圖3.13方法的值參數(shù)傳遞的運行結果(2).引用參數(shù)(ref)值類型參數(shù)傳遞的是實參值的副本,而引用型參數(shù)向方法傳遞的是實參的地址。在C#中,調用帶引用型參數(shù)的方法就可以在該方法的內部改變調用方法的實參數(shù)值了。帶引用型參數(shù)的方法頭格式:

[修飾符]返回的數(shù)據(jù)類型方法名(參數(shù)列表)

傳遞的參數(shù)格式:

ref參數(shù)的數(shù)據(jù)類型參數(shù)名從格式上看,與值傳遞不同的是在引用型參數(shù)的數(shù)據(jù)類型前加ref關鍵字。定義和調用引用型參數(shù)的方法時,在形參和實參前都必須加上ref關鍵字。默認情況下,基本數(shù)據(jù)類型為值類型,這意味著定義一個變量時,系統(tǒng)會從內存中分配特定的單元。而像類等類型默認為引用類型,這意味著類名包含的是類數(shù)據(jù)的存儲地址,而不是數(shù)據(jù)本身。方法的參數(shù)【例】程序中Sort方法的值參數(shù)傳遞方式改成引用參數(shù)傳遞,這樣在方法Sort中對參數(shù)x、y、z按從小到大的排序影響了調用它的實參a、b、c。usingSystem;classMyclass{publicvoidSort(refintx,refinty,refintz) { inttmp;//tmp是方法Sort的局部變量

//將x,y,z按從小到大排序

if(x>y){tmp=x;x=y;y=tmp;} if(x>z){tmp=x;x=z;z=tmp;} if(y>z){tmp=y;y=z;z=tmp;} }}classTest{staticvoidMain(){ Myclassm=newMyclass(); inta,b,c; a=30;b=20;c=10; m.Sort(refa,refb,refc); Console.WriteLine("a={0},b={1},c={2}",a,b,c); Console.Read();}}運行結果如圖所示:圖3.13方法的值參數(shù)傳遞的運行結果(3).輸出參數(shù)(out)C#還提供了一種特殊的參數(shù)傳遞方式,專門用于從方法返回數(shù)據(jù),完成這種數(shù)據(jù)傳遞方式的輸出型參數(shù),用關鍵字out表示。與引用型參數(shù)相似,輸出型參數(shù)也不另外開辟新的內存區(qū)域。它與引用型參數(shù)的差別在于:調用帶有out關鍵字參數(shù)的方法之前,不需要對傳遞給形參的實參值進行初始化。但是,在將實參作為輸出型參數(shù)傳遞的調用完成之后,該實參變量將會被方法中的形參明確賦值,并將數(shù)據(jù)從方法中傳出至調用處。在定義和調用輸出型參數(shù)的方法時,在形參和實參前都必須加上out關鍵字。

【例】在下面程序中,求一個數(shù)組元素中的最大值、最小值以及平均值。希望得到三個返回值,顯然用方法的返回值不能解決,而且這三個值必須通過計算得到,初始值沒有意義,所以解決方案可以定義三個out參數(shù)。usingSystem;classMyclass{

publicvoidMaxMinArray(int[]a,outintmax,outintmin,outdoubleavg) { intsum; sum=max=min=a[0]; for(inti=1;i<a.Length;i++) { if(a[i]>max)max=a[i]; if(a[i]<min)min=a[i]; sum+=a[i]; }avg=sum/a.Length; }}classTest{ staticvoidMain() { Myclassm=newMyclass(); int[]score={87,89,56,90,100,75,64,45,80,84}; intsmax,smin; doublesavg; m.MaxMinArray(score,outsmax,outsmin,outsavg); Console.Write("Max={0},Min={1},Avg={2}",smax,smin,savg); Console.Read(); }}運行結果如圖所示。ref和out參數(shù)的使用并不局限于值類型參數(shù),它們也可用于引用類型來傳遞對象。【例】下面程序定義了兩個方法,一個是Swap1,一個是Swap2,它們都有兩個引用對象作參數(shù),但Swap2的參數(shù)加了ref修飾,調用這兩個方法產生的結果是不一樣的。usingSystem;classMyclass{

publicvoidSwap1(strings,stringt) { stringtmp; tmp=s; s=t; t=tmp; } publicvoidSwap2(refstrings,refstringt) { stringtmp; tmp=s; s=t; t=tmp; }}classTest{ staticvoidMain() { Myclassm=newMyclass(); strings1="ABCDEFG",s2="134567"; m.Swap1(s1,s2); Console.WriteLine("s1={0}",s1);//s1,s2的引用并沒有改變

Console.WriteLine("s2={0}",s2); m.Swap2(refs1,refs2); //s1,s2的引用互相交換了

Console.WriteLine("s1={0}",s1); Console.WriteLine("s2={0}",s2); Console.Read(); }}運行結果如圖所示。(4).參數(shù)數(shù)組當方法的參數(shù)前帶有params關鍵字,這就是一個帶參數(shù)數(shù)組的方法。在方法的參數(shù)列表中使用params關鍵字,可用于表示方法的形參個數(shù)不確定,這樣可以在使用方法的過程中改變傳入方法實參的個數(shù)。關于參數(shù)數(shù)組,需掌握以下幾點。(1)若形參表中含一個參數(shù)數(shù)組,則該參數(shù)數(shù)組必須位于形參列表的最后;(2)參數(shù)數(shù)組必須是一維數(shù)組;(3)不允許將params修飾符與ref和out修飾符組合起來使用;(4)與參數(shù)數(shù)組對應的實參可以是同一類型的數(shù)組名,也可以是任意多個與該數(shù)組的元素屬于同一類型的變量;(5)若實參是數(shù)組則按引用傳遞,若實參是變量或表達式則按值傳遞。

【例7-5】參數(shù)數(shù)組的演示。請觀察并分析下列程序的執(zhí)行結果。

(程序代碼詳見例7-5)

[執(zhí)行結果]

4.方法的重載

方法重載是指同樣的一個方法名,有多種不同的實現(xiàn)方法。方法重載的格式是在一個類中兩次或多次定義同名的方法,這些同名的方法包括從基類繼承而來的方法,這些方法名稱相同,但每個方法的參數(shù)類型或個數(shù)不同,從而便于在用戶調用方法時系統(tǒng)能夠自動識別應調用的方法。這就是編譯時的多態(tài)性。

【例7-6】方法重載的演示。請觀察并分析下列程序的執(zhí)行結果。(程序代碼詳見例7-6)[執(zhí)行結果]

5.方法的覆蓋

在一個有繼承關系的類層次結構中,類中的方法由兩部分組成:一個是類體中聲明的方法,另一個則是直接從它的基類繼承而來的方法。但派生類很少會一成不變地繼承基類中所有方法,如果需要對基類的方法做出修改,就要在派生類中對基類方法進行覆蓋。1)采用new關鍵字修飾派生類中與基類同名的方法。

【例】方法覆蓋的演示。請觀察并分析下列程序的執(zhí)行結果。(程序代碼詳見覆蓋舉例fugai1)

從例中可以看出,使用關鍵字new修飾方法,可以在一個繼承的結構中隱藏有相同簽名的方法。但是正如程序中演示的基類對象A被引用到派生類對象B時,它訪問的仍是基類的方法。更多的時候,我們期望根據(jù)當前所引用的對象來判斷調用哪一個方法,這個判斷過程是在運行時進行的。5.方法的覆蓋

2)首先建基類的方法用關鍵字virtual修飾為虛方法,再由派生類用關鍵字override修飾與基類中虛方法具有相同簽名的方法,標明是對基類的虛方法重載。這就是運行時的多態(tài)性。【例】將上例改寫,在Shape類中方法area用virtual修飾,而派生類Triangle和Trapezia用關鍵字override修飾area方法,這樣就可以在程序運行時決定調用哪個類的area方法。程序代碼詳見覆蓋舉例fugai2具體使用過程應注意以下幾點:(1)不能將虛方法聲明為靜態(tài)的,因為多態(tài)性是針對對象的,不是針對類的。不能將虛方法聲明為私有的,因為私有方法不能被派生類覆蓋。(3)覆蓋方法必須與它相關的虛方法匹配,也就是說,它們的方法簽名(方法名稱、參數(shù)個數(shù)、參數(shù)類型)、返回類型以及訪問屬性等都應該完全一致。(4)一個覆蓋方法覆蓋的必須是虛方法,但它本身又是一個隱式的虛方法,所以它的派生類還可以覆蓋這個方法。不過盡管如此還是不能將一個覆蓋方法顯式地聲明為虛方法。7.1.5運算符重載

在C#中,運算符重載在類中進行聲明,聲明的格式如下。[格式]:返回值類型operator運算符(運算對象列表) {

重載的實現(xiàn)部分; };在C#中,可以重載的運算符主要有:+-!~++--truefalse*/%&|^<<>>==!=<><=>=不能重載的運算符有:.=&&||?:newtypeofsizeofis【例7-7】運算符重載的演示。請觀察并分析下列程序的執(zhí)行結果。

(程序代碼詳見例7-7)

[執(zhí)行結果]

7.1.9多態(tài)性

多態(tài)性是指同一操作作用于不同類的實例,這些類對它進行不同的解釋,從而產生不同的執(zhí)行結果的現(xiàn)象。在C#中有兩種多態(tài)性:編譯時的多態(tài)性和運行時的多態(tài)性。運行時的多態(tài)性是通過繼承和虛成員來實現(xiàn)的。運行時的多態(tài)性是指系統(tǒng)在編譯時不確定選用哪個重載方法,而是直到程序運行時,才根據(jù)實際情況決定采用哪個重載方法。編譯時的多態(tài)性具有運行速度快的特點,通過方法重載實現(xiàn),而運行時的多態(tài)性則具有極大的靈活性。運行時的多態(tài)性

如果希望基類中某個方法能夠在派生類中進一步得到改進,那么可以把這個方法在基類中定義為虛方法。類中的方法前加上了virtual修飾符成為虛方法,反之為非虛方法。使用了virtual修飾符后不允許再有static,abstract或override修飾符。普通方法重載要求方法名稱相同,參數(shù)類型和參數(shù)個數(shù)不同,而虛方法重載要求方法名稱、返回值類型、參數(shù)表中的參數(shù)個數(shù)、類型順序都必須與基類中的虛函數(shù)完全一致。在派生類中聲明對虛方法的重載要求在聲明中加上override關鍵字,而不能有new、static或virtual修飾符?!纠?-11】虛函數(shù)與多態(tài)性的演示。請觀察并分析下列程序的執(zhí)行結果。(程序代碼詳見例7-11)[執(zhí)行結果]

usingSystem;classBaseClass//基類{publicvoidNVMeth()//定義基類的非虛方法

{Console.WriteLine("調用了基類BaseClass類的非虛方法NVMeth");}publicvirtualvoidVMeth()//定義基類的虛方法

{Console.WriteLine("調用了基類BaseClass類的虛方法NMeth");}}classInClass:BaseClass//定義派生類{newpublicvoidNVMeth()//定義派生類的非虛方法,用new關閉警告

{Console.WriteLine("調用了派生類InClass類的非虛方法NVMeth");}publicoverridevoidVMeth()//定義派生類的虛方法,使用override進行重載

{Console.WriteLine("調用了派生類InClass類的虛方法NMeth");}}classTest{publicstaticvoidMain(){InClassInObj=newInClass();//生成派生類對象InObjBaseClassBaseObj=InObj;//把派生類InObj的對象賦值給基類的對象BaseObjBaseObj.NVMeth();//調用BaseClass類

BaseObj.VMeth();//調用InClassInObj.NVMeth();//調用InClassInObj.VMeth();//調用InClassBaseClassBaseObj1=newBaseClass();BaseObj1.NVMeth();//調用BaseClass類

BaseObj1.VMeth();//調用BaseClass

}}7.1.6域、屬性和索引器

1.域域又稱字段,它是類的一個成員,這個成員代表與對象或類相關的變量。域的定義格式如下。[格式]:[域修飾符]域類型域名;【例7-8】域的演示。請觀察并分析下列程序的執(zhí)行結果。(程序代碼詳見例7-8)[執(zhí)行結果]

2.屬性

屬性是對現(xiàn)實世界中實體特征的抽象,它提供了一種對類或對象特性進行訪問的機制。屬性的聲明格式如下。[格式]:[屬性修飾符]類型說明符屬性名{訪問聲明}

【例7-9】屬性的演示。請觀察并分析下列程序的執(zhí)行結果。(程序代碼詳見例7-9)[執(zhí)行結果]

3索引器使用索引器的目的是為了能夠像數(shù)組一樣訪問類中的數(shù)組型的對象。通過對對象元素的下標的索引,就可以訪問指定的對象。索引器類似于屬性,也是使用get關鍵字和set關鍵字定義了對被索引元素的讀寫權限,它們之間不同的是索引器有索引參數(shù)。【例】索引器示例。usingSystem;classMyClass{ privatestring[]data=newstring[5]; //索引器定義,根據(jù)下標訪問data publicstringthis[intindex] { get { returndata[index]; } set { data[index]=value; } }}classMyClient{ publicstaticvoidMain() { MyClassmc=newMyClass(); //調用索引器set賦值

mc[0]="Rajesh"; mc[1]="A3-126"; mc[2]="Snehadara"; mc[3]="Irla"; mc[4]="Mumbai";//調用索引器get讀出

Console.WriteLine("{0},{1},{2},{3},{4}",mc[0],mc[1],mc[2],mc[3],mc[4]); }}

運行結果如下:

Rajesh,A3-126,Snehadara,Irla,Mumbai索引器的get和set中可以增加各種計算和控制代碼。7.1.7this關鍵字

this關鍵字用來引用類的當前實例,成員通過this關鍵字可以知道自己屬于哪一個實例。this關鍵字只能用在類的構造函數(shù)、類的實例方法中,在其它地方(如靜態(tài)方法中)使用this關鍵字均是錯誤的。以下是this的常用用途。(1)限定被相似的名稱隱含的成員,例如:classc1{privatestringname;publicEmployee(stringname,stirngalias){=name;this.alias=alias;}}(2)將對象作為參數(shù)傳遞到其他方法,例如:CalcTax(this);(3)聲明索引器,例如:publicintthis[intindex]{get{returnarray[index];}set{array[index]=value;}}事件事件作為C#中的一種類型,為類和類的實例定義發(fā)出通知的能力,從而將事件和可執(zhí)行代碼捆綁在了一起。事件最常見的用途是用于窗體編程,當發(fā)生像點擊按鈕、移動鼠標等事件時,相應的程序將收到通知,再執(zhí)行代碼。

C#事件是按“發(fā)布-預訂”的方式工作。先在一個類中公布事件,然后就可以在任意數(shù)量的類中對事件預訂。事件的工作過程可以用圖4.12表示:圖4.12事件的工作圖事件C#事件機制是基于委托實現(xiàn)的,因此要首先定義一個委托EventHandler:

publicdelegatevoidEventHandler(objectfrom,myEventArgse)System.EventArgs是包含事件數(shù)據(jù)的類的基類,在代碼中可直接使用EventArgs類。myEventArgs類派生于EventArgs類,實現(xiàn)自定義事件數(shù)據(jù)的功能。這里from表示發(fā)生事件的對象。定義事件格式為:

event事件的委托名事件名如事件TextOut定義:

publiceventEventHandlerTextOut;事件的激活一般寫成:

if(TextOut!=null)TextOut(this,newEventArgs());

檢查TextOut事件有沒有被訂閱,如不為null,則表示有用戶訂閱。訂閱事件的是TestApp類,首先實例化EventSource,然后訂閱事件:

evsrc.TextOut+=newEventSource.EventHandler(CatchEvent);也可以取消訂閱:

evsrc.TextOut-=newEventSource.EventHandler(CatchEvent);事件【例】事件示例。usingSystem;//定義事件包含數(shù)據(jù)publicclassMyEventArgs:EventArgs{ privatestringStrText; publicMyEventArgs(stringStrText) { this.StrText=StrText; } publicstringGetStrText { get { returnStrText; } }}【例】//發(fā)布事件的類classEventSource{ MyEventArgsEvArgs=newMyEventArgs("觸發(fā)事件");//定義委托

publicdelegatevoidEventHandler(objectfrom,MyEventArgse);//定義事件

publiceventEventHandlerTextOut; //激活事件的方法

publicvoidTriggerEvent() { if(TextOut!=null) TextOut(this,EvArgs); }}【例】//訂閱事件的類classTestApp{ publicstaticvoidMain() { EventSourceevsrc=newEventSource(); //訂閱事件

evsrc.TextOut+=newEventSource.EventHandler(CatchEvent);//觸發(fā)事件

evsrc.TriggerEvent(); Console.WriteLine("------");//取消訂閱事件

evsrc.TextOut-=newEventSource.EventHandler(CatchEvent); //觸發(fā)事件

evsrc.TriggerEvent(); //事件訂閱已取消,什么也不執(zhí)行【例】Console.WriteLine("------"); TestApptheApp=newTestApp(); evsrc.TextOut+=newEventSource.EventHandler(theApp.InstanceCatch); evsrc.TriggerEvent(); Console.WriteLine("------"); } //處理事件的靜態(tài)方法

publicstaticvoidCatchEvent(objectfrom,MyEventArgse) { Console.WriteLine("CathcEvent:{0}",e.GetStrText); } //處理事件的方法

publicvoidInstanceCatch(objectfrom,MyEventArgse) { Console.WriteLine("InstanceCatch:{0}",e.GetStrText); }}【例】運行結果如圖4.13所示。

EventHandler是一個委托聲明如下

public

delegate

void

EventHandler(

object

sender

,

EventArgs

e

)

注意這里的參數(shù),前者是一個對象(其實這里傳遞的是對象的引用,如果是button1的click事件則sender就是button1),后面是包含事件數(shù)據(jù)的類的基類。

下面我們研究一下Button類看看其中的事件聲明(使用WinCV工具查看),以Click事件為例。

public

event

EventHandler

Click;

這里定義了一個EventHandler類型的事件Click

前面的內容都是C#在類庫中已經為我們定義好了的。下面我們來看編程時產生的代碼。

private

void

button1_Click(object

sender,

System.EventArgs

e)

{

...

}

這是我們和button1_click事件所對應的方法。注意方法的參數(shù)符合委托中的簽名(既參數(shù)列表)。那我們怎么把這個方法和事件聯(lián)系起來呢,請看下面的代碼。

this.button1.Click

+=

new

System.EventHandler(this.button1_Click);

把this.button1_Click方法綁定到this.button1.Click事件。ButtonClick事件7.1.8類的繼承

繼承是面向對象程序設計中實現(xiàn)代碼重用的重要機制之一,它起源于現(xiàn)實世界中事物之間的聯(lián)系。類的繼承的基本格式與功能如下。

[格式]:

class派生類類名:基類類名

{成員聲明列表;}【例7-10】類繼承的演示。請觀察并分析下列程序的執(zhí)行結果。(程序代碼詳見例7-10)

[執(zhí)行結果]

抽象類

抽象類是基類的一種特殊類型。除了擁有普通的類成員之外,還有抽象類成員。抽象類成員中的方法和屬性,只有聲明(使用關鍵字abstract),而沒有實現(xiàn)部分。由于對實例而言,沒有實現(xiàn)的成員是不合法的,所以抽象類永遠也不能實例化。這種不能實例化的類也有它的作用空間,它們可以在類層次結構的上層,對于派生于該類的其他類而言,抽象類就確定了子類的基本結構和意義,從而使程序框架更容易建立。抽象類

包含一個或多個抽象函數(shù)的類本身必須聲明為abstract,但是,抽象類可以包含非抽象的成員。從抽象類派生的類必須對基類中包含的所有抽象方法提供實現(xiàn)過程,否則,它也為抽象類。抽象函數(shù)為隱式的虛函數(shù),所以為繼承的抽象類提供了實現(xiàn)代碼的方式與覆蓋一個虛方法相似。另外,屬性和索引也可以聲明為abstract。密封類

上面介紹的種種例子無不說明繼承的作用顯著,但有時候,我們并不希望自己編寫的類被繼承,或者已經認定沒有必要繼承了。于是,C#提出了密封類(sealedclass)的概念。類聲明為密封后,就不能用來派生新的類。密封類

密封類具有不能用來繼承的限制,但它也有自身的長處。一個類聲明為密封的(sealed)有利于提高穩(wěn)定性。因為,繼承性是對基類的內部的某種程度的保護性訪問。如果類是密封的,那么就完全避免了由派生類引起崩潰的可能性。同時,編譯器也能針對密封類做相應的優(yōu)化,例如,可以避免增加與虛擬方法相關聯(lián)的系統(tǒng)總開銷。

接口1.接口介紹接口是用來定義一種程序的協(xié)定。接口好比一種模版,這種模版定義了實現(xiàn)接口的對象必須實現(xiàn)的方法,其目的就是讓這些方法可以作為接口實例被引用。接口的定義如:

publicinterfaceIPartA { voidSetDataA(stringdataA); }接口使用關鍵字interface定義,接口可以使用的修飾符包括new,public,protected,internal,private等。接口的命名通常是以I開頭,如IPartA,IPartB。接口的成員可以是方法、屬性、索引器和事件,但不可以有任何的成員變量,也不能在接口中實現(xiàn)接口成員。接口不能被實例化。接口的成員默認是公共的,因此不允許成員加上修飾符?!纠拷涌谘菔尽singSystem;//定義接口IPartApublicinterfaceIPartA{ voidSetDataA(stringdataA);}//定義接口IPartB,繼承IPartApublicinterfaceIPartB:IPa

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論