版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認(rèn)領(lǐng)
文檔簡介
第6章面向?qū)ο笤O(shè)計
6.1面向?qū)ο蠡靖拍?.2類的定義和使用6.3靜態(tài)變量和靜態(tài)函數(shù)6.4繼承6.5多態(tài)6.6屬性6.7知識拓展6.8習(xí)題6.1.1對象的概念
在日常生活中,對象是指可辨識的一種實體。例如汽車、房子、書、文檔和支票等。現(xiàn)實世界的對象都有特征和行為,如“汽車”對象的一部分特性為:顏色、重量、型號、車輪數(shù)目、發(fā)動機功率?!捌嚒蹦軌驁?zhí)行的動作是:啟動、加速、倒車。6.1面向?qū)ο蠡靖拍?/p>
6.1.2類的概念
在現(xiàn)實世界中,不同的事物分屬不同的類別,比如狗屬于寵物類,龍蝦屬于海鮮類,也就是說現(xiàn)實世界中的對象是分類別的。
在編程世界中,將相似的對象或具有相同特性的對象歸為一個類??梢詫㈩惗x為具有相同特征、共同行為和共同關(guān)系的一組對象的抽象。如果使用藍(lán)圖作比喻,那么類就是藍(lán)圖,對象就是基于該藍(lán)圖的建筑。類定義的對象必然擁有該類的特征。每個對象稱為它所屬的類的實例,例如在稱為“人”的類中,具體的個人(例如張三、李四、王二等)都是
對象。類的基本要素包括數(shù)據(jù)和方法。
數(shù)據(jù)表示對象的特性,例如,一個類中的每個人都有姓名、年齡,并可能有一份工作。這些是類中所有人的具有的相同特性。
方法是類中所有的對象執(zhí)行的某些共同動作或操作,比如人有走的動作,魚有游的動作,電視機可以有播放的動作。在編程世界中,必須以程序化的方式在相應(yīng)的類中表示對象擁有的動作。6.2.1使用類的基本步驟
(1)定義類。在類的定義中需要使用關(guān)鍵字class,其簡單的定義格式為:
[訪問修飾符]class類名稱[:[基類][,接口序列]]
{
[字段聲明]
[構(gòu)造函數(shù)]
[方法]
[事件]
}
其中,[]中的內(nèi)容可省略。6.2類的定義和使用
在類的定義中,包含有各種類成員,概括起來類的成員有兩種:存儲數(shù)據(jù)的成員與操作數(shù)據(jù)的成員。存儲數(shù)據(jù)的成員叫“字段”,“字段”是類定義中的數(shù)據(jù),也叫類的變量;操作數(shù)據(jù)成員又有很多種,如“屬性”、“方法”與“構(gòu)造函數(shù)”,方法實質(zhì)上就是函數(shù),通常用于對字段進行計算和操作,即對類中的數(shù)據(jù)進行操作,以實現(xiàn)特定的功能。
下面代碼段定義了一個鴨子類,鴨子具有顏色、重量等特征以及走路、吃食物等行為。
classDuck
{
publicstringcolor; //特征:顏色
publicfloatweight; //特征:重量
publicvoidwalk() //行為:走路
{
Console.WriteLine("我正在走路");
}
publicvoideat() //行為:吃食物
{
Console.WriteLine("我正在吃東西");
}
publicvoiddisplay() //顯示信息
{
Console.WriteLine("我的顏色是{0},我的重量為{1}",color,weight);
}
}
(2)聲明對象。聲明對象的格式為:
類名對象名;
例如,下面語句聲明一個Duck的對象duck:
Duckduck;
(3)實例化對象。對象是類的實例,可以使用類中提供的方法。創(chuàng)建類的對象的操作,被稱為類的實例化。用new關(guān)鍵字來創(chuàng)建對象。
實例化的語法格式為:
對象名=new類名(參數(shù));
例如,下面語句聲明并創(chuàng)建了一個Duck的對象duck:
Duckduck=newDuck();
(4)訪問對象。訪問對象的實質(zhì)是訪問對象的成員,訪問對象的成員使用“.”運算符。例如:
car.weight=20;//把car對象的重量設(shè)為30
car.display();//調(diào)用car對象的display方法
【例6-1】定義一個鴨子類,鴨子具有顏色、重量等特征以及走路、吃食物等行為。并創(chuàng)建一個顏色為黃色、重量為30的鴨子實例。usingSystem;
classDuck
{
publicstringcolor;
publicfloatweight;
publicvoidwalk()
{
Console.WriteLine("我正在走路");
}
publicvoideat()
{
Console.WriteLine("我正在吃東西");
}
publicvoiddisplay(){
Console.WriteLine("我的顏色是{0},我的重量為{1}",color,weight);
}
}
classClass1
{
staticvoidMain(string[]args)
{
Duckduck=newDuck();//聲明并實例化Duck
duck.color="黃色";
duck.weight=30;
duck.walk();
duck.eat();
duck.display();
}
}運行結(jié)果如圖6-1所示。圖6-1例6-1運行結(jié)果
【例6-2】定義一個長方形,要求有長方形尺寸信息,并能計算面積。并創(chuàng)建一個長為5、寬為4的長方形實例。
usingSystem;
classRectangle
{
publicdoublelength;
publicdoublewidth;
publicdoubleArea(){returnlength*width;}
}
classClass1
{
staticvoidMain(string[]args)
{
Rectanglerect=newRectangle();
rect.length=5;
rect.width=4;
Console.WriteLine("長方形的面積為:"+rect.Area());
}
}
運行結(jié)果如圖6-2所示。圖6-2例6-2運行結(jié)果6.2.2類的封裝性和類成員的訪問權(quán)限
1.類的封裝性
在面向?qū)ο缶幊讨?,封裝是指把屬性和方法(數(shù)據(jù)和操縱這些數(shù)據(jù)的代碼)一起封藏在一個公共結(jié)構(gòu)中。設(shè)計類時,可以指定某些數(shù)據(jù)和方法是私有的,而另外一些數(shù)據(jù)和方法是公有的。
可以把對象想象成黑箱子,作為對象的用戶,不需要查看黑箱子的內(nèi)部。類有許多特性和方法,用戶不能夠訪問所有這些特性和方法,只能訪問對象所公開的特性和方法。比如某個人,我們可以了解該人的外貌特征,但是卻不能訪問該人的隱私。
通過隱藏用戶不需要的信息(如實現(xiàn)細(xì)節(jié)),可以讓用戶專注于對象中對他們有用的特性。例如,電話機外殼把電話機的電線、元器件封裝起來,人們可以使用電話機,而無需知道電話機的內(nèi)部工作機制。
在設(shè)計類時,應(yīng)該盡量隱藏實現(xiàn)細(xì)節(jié),只公開那些類使用者需要知道的操作和數(shù)據(jù)。
2.類成員的訪問權(quán)限
類成員的訪問權(quán)限用來控制外界對某一個類成員的訪問。
C#?中常用的訪問修飾符及其意義如下:
●?public——訪問不受限制,可以被任何其他類訪問。
●?protected——在類及所有的派生類中可以訪問該成員,不允許外部訪問。
●?private——僅僅在同一個類的內(nèi)部才能訪問該成員。甚至派生類都不能訪問它。
●?Internal——只有在同一程序集中的文件內(nèi)才是可訪問的。
●?protectedinternal——只限于當(dāng)前項目,或者從該項目中的類繼承的類才可以訪問。
如果聲明成員時沒有使用任何訪問修飾符,則該成員被認(rèn)為是私有的(private)。類的缺省訪問修飾符是Internal。【例6-3】訪問修飾符的作用。
usingSystem;
classCar
{
protectedstringcolor;
privatefloatweight;
voiddisplay()
{
Console.WriteLine(“我的顏色是{0},我的重量為{1}”,color,
weight);
}
}
classClass1
{
staticvoidMain(string[]args)
{
Carcar=newCar();
car.color="red"; //不正確
car.weight=30; //不正確,因為weight為private
car.display(); //不正確,因為display()為默認(rèn)的pivate
}
}
編譯錯誤提示如圖6-3所示。圖6-3編譯錯誤提示6.2.3構(gòu)造函數(shù)與析構(gòu)函數(shù)
1.構(gòu)造函數(shù)
構(gòu)造函數(shù)是一個特殊的方法,用于在建立對象時進行初始化的操作,每當(dāng)創(chuàng)建一個對象時,都會先調(diào)用類中定義的構(gòu)造函數(shù)。使用構(gòu)造函數(shù)的好處是能夠確保每一個對象在被使用之前都適當(dāng)?shù)剡M行了初始化。
構(gòu)造函數(shù)還具有以下特點:
●每個類至少有一個構(gòu)造函數(shù)。若程序代碼中沒有構(gòu)造函數(shù),則系統(tǒng)會自動提供一個默認(rèn)的構(gòu)造函數(shù)。
●構(gòu)造函數(shù)總是和它的類名相同。
●構(gòu)造函數(shù)不允許有返回類型(包括void類型)?!纠?-4】改進長方形類,利用構(gòu)造函數(shù)初始化長方形的信息。
usingSystem;
classRectangle
{
publicdoublelength;
publicdoublewidth;
publicRectangle(doublel,doublew) //構(gòu)造函數(shù)
{
length=l;
width=w;
}
publicdoubleArea(){returnlength*width;}
}
classClass1
{
staticvoidMain(string[]args)
{
Rectanglerect=newRectangle(5,4); //創(chuàng)建一個長為5、寬為4的長方形實例
Console.WriteLine("長方形的面積為:"+rect.Area());
}
}
運行結(jié)果如圖6-4所示。圖6-4例6-4運行結(jié)果
2.默認(rèn)構(gòu)造函數(shù)
如果在類中不定義構(gòu)造函數(shù),則系統(tǒng)會提供一個默認(rèn)的構(gòu)造函數(shù)。默認(rèn)構(gòu)造函數(shù)沒有參數(shù)。
對于一些類中的數(shù)據(jù)成員變量,如果聲明變量的時候沒給變量賦初始值,默認(rèn)構(gòu)造函數(shù)自動初始化。變量默認(rèn)初始值見表6-1。表6-1變量默認(rèn)初始值
3.析構(gòu)函數(shù)
析構(gòu)函數(shù)用于銷毀類的實例,釋放被這些類實例所占用的資源。析構(gòu)函數(shù)具有如下特點:
●函數(shù)名稱與類名稱相同,但應(yīng)在其前面加上符號“~”。
●析構(gòu)函數(shù)沒有任何參數(shù)。
●也不返回任何值。析構(gòu)函數(shù)是自動調(diào)用的,程序員無法控制何時調(diào)用析構(gòu)函數(shù),調(diào)用析構(gòu)函數(shù)的決定是由一個特殊的被稱為垃圾回收器的C#?程序來完成的。原因是如果把銷毀對象的工作全部交給編程者通過調(diào)用析構(gòu)函數(shù)完成,而系統(tǒng)不自動實現(xiàn),一旦編程者忘記銷毀對象,就會引起內(nèi)存泄漏問題,所以采用垃圾回收機制自動銷毀不再使用的對象。垃圾回收機制是在適當(dāng)?shù)臅r候自動回收不再使用的內(nèi)存的,即檢測到?jīng)]有被引用的對象,然后銷毀之。
注意,雖然C#?不允許在程序中直接調(diào)用析構(gòu)函數(shù)來銷毀對象,但可以調(diào)用安全的Dispose方法來銷毀對象,在對性能要求比較高的場合,調(diào)用Dispose方法來直接銷毀對象還是很有用的。
析構(gòu)函數(shù)不能重載,也不能被繼承,并且前面不能帶有public等修飾符。定義格式如下:class類名
{
~類名()//定義析構(gòu)函數(shù)
{
…//析構(gòu)函數(shù)體
}
}
【例6-5】為Car類增加析構(gòu)函數(shù),析構(gòu)函數(shù)向控制臺輸出“調(diào)用析構(gòu)函數(shù)”。
usingSystem;
classCar
{
publicstringcolor;
publicfloatweight;
publicCar(stringcolor,floatweight)
{
this.color=color;
this.weight=weight;
Console.WriteLine("調(diào)用構(gòu)造函數(shù)");
}
publicvoidprint(){
Console.WriteLine("我的顏色是{0},我的重量為{1}",color,weight);
}
~Car()
{
Console.WriteLine("調(diào)用析構(gòu)函數(shù)");
}
}
classClass1圖6-5例6-5運行結(jié)果
{
staticvoidMain(string[]args)
{
Carcar=newCar("red",30);
car.print();
}
}
運行結(jié)果如圖6-5所示。圖6-5例6-5運行結(jié)果6.3.1靜態(tài)變量
靜態(tài)變量為類的所有實例所共享,無論這個類創(chuàng)建了多少個實例,一個靜態(tài)成員在內(nèi)存中只占有一塊區(qū)域。靜態(tài)變量用“類名.靜態(tài)變量”名來訪問。6.3靜態(tài)變量和靜態(tài)函數(shù)【例6-6】用靜態(tài)變量記錄對象的創(chuàng)建個數(shù)。
usingSystem;
publicclassStaticTest
{
publicstaticintinstanceCount; //靜態(tài)變量,用于記錄對象的創(chuàng)建個數(shù)
publicintnumber; //實例變量
publicStaticTest()
{
instanceCount=instanceCount+1;//對象計數(shù)加1
number=number+1;
}
}
classMainTest
{
publicstaticvoidMain()
{
newStaticTest();
newStaticTest();
StaticTestobj=newStaticTest();
Console.WriteLine("number={0}對象數(shù)={1}",obj.number,StaticTest.instanceCount);
}
}
運行結(jié)果如圖6-6所示。圖6-6例6-6運行結(jié)果6.3.2靜態(tài)方法
靜態(tài)方法是一種特殊的成員方法,它不屬于類的某一個具體的實例,靜態(tài)方法用“類名.方法名()”來訪問。
非靜態(tài)方法可以訪問類中的任何成員,而靜態(tài)方法只能訪問類中的靜態(tài)成員?!纠?-7】求n!,用靜態(tài)方法實現(xiàn)。
usingSystem;
publicclassStaticTest2
{
publicstaticlongfact(intn)
{
intsum=1;
for(inti=1;i<=n;i++)
sum=sum*i;
}
returnsum;
}
}
classClass1
{
staticvoidMain(string[]args)
{
Console.WriteLine("5的階乘為{0}",StaticTest2.fact(5));
}
}
運行結(jié)果如圖6-7所示。圖6-7例6-7運行結(jié)果程序說明:
程序中,由于fact方法為靜態(tài)方法,因此調(diào)用時采用類名.方法名()的方法,即采用StaticTest2.fact(3)。注意,靜態(tài)方法不能通過對象來調(diào)用,以下寫法錯誤:
StaticTest2obj=newStaticTest2();
Console.WriteLine("3的階乘為{0}",obj.fact(3));6.4.1類的繼承性
在現(xiàn)實世界中,我們經(jīng)常談到“張三像他父親,李四像他母親”,其實這就是對象之間的繼承關(guān)系在現(xiàn)實世界的體現(xiàn)?!皬埲袼赣H”的含義就是張三繼承了他父親的一些特征。繼承關(guān)系在現(xiàn)實世界中廣泛存在,如動物這個類可以分為哺乳動物、兩棲動物、昆蟲、爬行動物等。不管怎樣分類,哺乳動物、兩棲動物、昆蟲、爬行動物都會繼承動物的基本特征和基本行為,同樣對于哺乳動物,不管是貓還是狗,它們都會繼承哺乳動物的基本特征。6.4繼承在面向?qū)ο缶幊讨校瑥牧硪粋€類繼承數(shù)據(jù)和方法的類稱為子類,被繼承的類稱為父類。每個子類與父類具有共同的特性。例如,汽車類中的所有車輛可能都有類似的特性:都具備車輪和發(fā)動機。此外,子類可擁有它自己的特定特征。例如,公共汽車有供人坐的座位,而卡車擁有裝貨物的空間。
繼承性是類的基本特征之一,通過繼承,子類可以重用父類的代碼,這樣就達(dá)到了代碼重用的目的。所謂類的繼承性就是在類的基礎(chǔ)上創(chuàng)建新類,新類的成員包括從已有的類中繼承的成員、重新定義或者加入的新成員。繼承提高了代碼的重用性,從而提高了程序設(shè)計的效率。6.4.2定義子類
創(chuàng)建子類要在子類的名字后面加上冒號“:”,后面再跟上基類的名字。創(chuàng)建子類使用的語法如下:
[訪問修飾符]class派生類名稱:基類名稱
{
…//程序代碼
}在C#?中,類的繼承遵循以下規(guī)則:
●子類只能繼承一個基類。
●子類繼承基類的成員,但不能繼承基類的構(gòu)造函數(shù)和析構(gòu)函數(shù)。
●類的繼承可以傳遞。例如,假設(shè)C類繼承B類,B類又繼承A類,那么C類即具有了B類與A類的成員。在C#?中,Object類是所有類的基類,也就是說所有的類都具有Object類的成員。
●子類是對基類的擴展,子類定義中可以聲明新的成員,但不能消除已繼承的基類成員。
●基類中的成員聲明時,不管其是什么訪問控制方式,總能被子類繼承,訪問控制的不同只決定子類成員是否能夠訪問基類成員。
●子類定義中如果聲明了與基類同名的成員,則基類的同名成員將被覆蓋,從而使子類不能直接訪問同名的基類的成員?!纠?-8】定義一個形狀類Shape的子類Circle。
usingSystem;
publicclassShape
{
publicstringColor;
publicvoiddisplay()
{
Console.WriteLine("顏色為{0}",Color);
}
}
publicclassCircle:Shape
{
doubleradius;//半徑 publicCircle(stringcolor,doubleradius)
{
this.Color=color;
this.radius=radius;
}
publicdoublegetArea()//計算面積
{
returnMath.PI*radius*radius;
}
}
classClass1
{
staticvoidMain(string[]args)
{
Circlecircle=newCircle("red",3);
Console.WriteLine("面積為{0}",circle.getArea());
circle.display();
}
}
運行結(jié)果如圖6-8所示。圖6-8例6-8運行結(jié)果6.4.3使用protected訪問方式
如果一個類需要讓它的子類訪問特定的變量、屬性和方法,但是不允許任何其他類訪問它們,那么可以將它們標(biāo)記為protected。
【例6-9】使用protected修飾符。usingSystem;
classAnimal
{
publicintnumLegs;
protectedstringname;
privateintcolor;
}
classDog:Animal
{
vpublicvoidSetAll()
{
numLegs=4; //合法,因為numLegs是public數(shù)據(jù)
name=“小黃”; //合法,因為name是protected數(shù)據(jù),子
類可以訪問
color=2;//不合法,因為color是private數(shù)據(jù),子類不能訪問
}
}
classClass1
{
publicstaticvoidMain()
{
Animala=newAnimal();
a.numLegs=2;
=“Animal”; //不合法,因為name是protected數(shù)據(jù),
外部類不能訪問
a.color=2; //不合法,因為color是private數(shù)據(jù),外
部類不能訪問
Dogd=newDog();
d.SetAll();
}
}
運行結(jié)果如圖6-9所示。圖6-9例6-9運行結(jié)果6.4.4子類的構(gòu)造函數(shù)和析構(gòu)函數(shù)
子類不繼承基類的構(gòu)造函數(shù)和析構(gòu)函數(shù)。子類在創(chuàng)建對象時將執(zhí)行其默認(rèn)的構(gòu)造函數(shù),該默認(rèn)的構(gòu)造函數(shù)首先通過base關(guān)鍵字調(diào)用其直接基類的默認(rèn)構(gòu)造函數(shù),然后再調(diào)用子類的構(gòu)造函數(shù)。
子類的構(gòu)造函數(shù)格式如下:
[修飾符]子類名(形參表)[:base(實參表)]{}
其中,base(實參表)表示調(diào)用基類的有參構(gòu)造函數(shù)。base關(guān)鍵字主要是為子類調(diào)用基類成員提供一個簡寫的方法。
傳遞給基類構(gòu)造函數(shù)的“實參列表”通常包含在子類構(gòu)造函數(shù)的“形參列表”中。子類在創(chuàng)建對象時構(gòu)造函數(shù)的執(zhí)行順序為:先執(zhí)行基類的構(gòu)造函數(shù),然后執(zhí)行子類的構(gòu)造函數(shù)?!纠?-10】子類的構(gòu)造函數(shù)。
usingSystem;
publicclassBaseClass
{
publicBaseClass()
{
Console.WriteLine("正在執(zhí)行基類的BaseClass()");
}
publicBaseClass(inti)
{
Console.WriteLine("正在執(zhí)行基類的BaseClass(inti)");
}
}
publicclassDerivedClass:BaseClass
{
//調(diào)用基類無參數(shù)的構(gòu)造函數(shù)
publicDerivedClass()
:base()
{
Console.WriteLine("正在執(zhí)行子類的DerivedClass()");
}
//調(diào)用基類帶參數(shù)的構(gòu)造函數(shù)
publicDerivedClass(inti)
:base(i)
{
Console.WriteLine("正在執(zhí)行子類的DerivedClass(inti)");
}
}
classProgram
{
staticvoidMain(string[]args)
{
DerivedClassmd=newDerivedClass();
DerivedClassmd1=newDerivedClass(1);
}
}
運行結(jié)果如圖6-10所示。圖6-10例6-10運行結(jié)果【例6-11】子類的析構(gòu)函數(shù)。
usingSystem;
classFirst
{publicFirst()
{
Console.WriteLine("調(diào)用First的構(gòu)造函數(shù)");
}
~First()
{
System.Console.WriteLine("調(diào)用First的析構(gòu)函數(shù)");
}
}
classSecond:First
{
publicSecond()
{
Console.WriteLine("調(diào)用Second的構(gòu)造函數(shù)");
}
~Second()
{
System.Console.WriteLine("調(diào)用Second的析構(gòu)函數(shù)");
}
}
classProgram
{
staticvoidMain(string[]args)
{
Console.WriteLine("調(diào)用構(gòu)造函數(shù)和析構(gòu)函數(shù)的順序是:");
Secondt=newSecond();
}
}
運行結(jié)果如圖6-11所示。圖6-11例6-11運行結(jié)果6.5.1類的多態(tài)性
多態(tài)指對象和行為綁定的多樣性,多態(tài)意味著相同的方法在不同的類上具有不同的行為。如類shape是圖形類,三角形、圓和立方體都是圖形類的子類。假定類shape有一個方法Draw,該方法可以繪制圖形本身。對于三角形、圓和立方體,由于繼承父類的行為,因此三角形、圓和立方體也有Draw法能夠繪制圖形本身,但是這三者所執(zhí)行的動作,所達(dá)到的結(jié)果卻不一樣。三角形將繪制出三角形,圓將繪制出圓,立方體將繪制出立方體。
6.5多態(tài)在C#?中支持兩種多態(tài)性:
(1)編譯時的多態(tài)性,這種多態(tài)性是通過進行方法重載和操作符重載來實現(xiàn)的。
(2)運行時的多態(tài)性,運行多態(tài)性是直到運行時系統(tǒng)才根據(jù)實際情況決定采用何種操作。運行多態(tài)性一般借助接口、抽象類或虛方法實現(xiàn)。6.5.2方法重載
實現(xiàn)用同名的方法對不同類型的數(shù)據(jù)做不同的運算,就稱為方法重載。其實,我們非常熟悉的Console類之所以能夠?qū)崿F(xiàn)對字符串進行格式化的功能,就是因為已定義了多個重載的成員方法:
publicstaticvoidWriteLine();
publicstaticvoidWriteLine(int);
publicstaticvoidWriteLine(float);
publicstaticvoidWriteLine(long);
這樣程序代碼就會顯得相對簡單,在編寫程序時就不用為不同類型數(shù)據(jù)去考慮使用哪一種方法名了。當(dāng)在程序中要調(diào)用重載方法時,C#匹配重載方法的依據(jù)有以下三個方面:
●參數(shù)表中的參數(shù)類型。
●參數(shù)個數(shù)。
●參數(shù)順序。
所以在定義重載方法時,所有重載的方法都必須在上述內(nèi)容中至少有一項不同,否則將出錯。例如,在定義重載方法時,如果兩個方法具有相同的參數(shù)列表,而只是返回值的類型不同,則編譯時會出錯。下面兩個函數(shù)不是重載,編譯不能通過:
publicvoidprint(intx)
publicintprint(intx)【例6-12】編寫求兩個整數(shù)和兩個字符中較大值的函數(shù)。
usingSystem;
classClass1
{
publicintMax(intx,inty) //求兩個整數(shù)較大值
{
returnx>y?x:y;
}
publiccharMax(charx,chary) //求兩個字符較大值
{returnx>y?x:y;}
staticvoidMain(string[]args)
{
Class1class1=newClass1();inti,j;
Console.Write("請輸入第一個數(shù):");
i=int.Parse(Console.ReadLine());
Console.Write("請輸入第二個數(shù):");
j=int.Parse(Console.ReadLine());
Console.WriteLine("較大的整數(shù)為:"+class1.Max(i,j));
chara,b;
a=char.Parse(Console.ReadLine());
b=char.Parse(Console.ReadLine());
Console.WriteLine("較大的字符為:"+class1.Max(a,b));
}
}
運行結(jié)果如圖6-12所示。圖6-12例6-12運行結(jié)果6.5.3構(gòu)造函數(shù)重載
有時候初始化類時需要從外部傳數(shù)據(jù)進來,這時無參數(shù)的構(gòu)造函數(shù)就不能勝任了,解決這個問題的辦法就是重載(Overloading)構(gòu)造函數(shù)。
例如,在創(chuàng)建一個長方形對象時,可能需要創(chuàng)建一個長方形的特例正方形,這時僅需要給定一個邊長參數(shù)即可,因此需要一個只接受一個參數(shù)的構(gòu)造函數(shù),那么可以再聲明一個含一個參數(shù)的構(gòu)造函數(shù),創(chuàng)建對象時,根據(jù)給定的參數(shù)個數(shù)將對象初始化為長方體或正方體?!纠?-13】構(gòu)造函數(shù)重載的長方形類。
usingSystem;
classRectangle
{
publicdoublelength;
publicdoublewidth;
publicRectangle(doublel,doublew)
{
length=l;
width=w;
}
publicRectangle(doublesize)
{
length=size;
width=size;
}
publicdoubleArea(){returnlength*width;}
}
classClass1
{
staticvoidMain(string[]args)
{
Rectanglerect=newRectangle(5,4);
Console.WriteLine("長方形的面積為:"+rect.Area());
Rectanglerect2=newRectangle(5);
Console.WriteLine("長方形的面積為:"+rect2.Area());
}
}
運行結(jié)果如圖6-13所示。圖6-13例6-13運行結(jié)果6.5.4虛函數(shù)
如果希望基類中的某個方法能夠在子類中進一步得到改進,那么可以把這個方法定義為虛方法。
在基類的定義中,通過virtual關(guān)鍵字來說明該方法為虛方法,如:
publicvirtualvoidmyMethod()
{
…//程序代碼
}如果在子類中要重載基類方法,那么需要使用override關(guān)鍵字,如:
publicoverridevoidmyMethod()
{
…//程序代碼
}
使用虛函數(shù)與重寫方法時,需要注意下面幾個方面:
(1)虛函數(shù)不能聲明為靜態(tài)(static)的。因為靜態(tài)的方法是應(yīng)用在類這一層次的,而多態(tài)性只能在對象上運作。
(2)?virtual不能和private一起使用。因為聲明為private就無法在子類中重寫了。
(3)重寫方法的名稱、參數(shù)個數(shù)、類型以及返回值都必須和虛方法的一致。
【例6-14】編寫Animal類及其兩個子類Lion和Rabbit。要求使用虛函數(shù)。
usingSystem;
classAnimal
{
publicvirtualvoidFeed()//定義基類的虛方法
{
Console.WriteLine("我吃食物.");
}
newpublicvoidFeed2()//定義基類的非虛方法
{
Console.WriteLine("我吃食物.");
}
}
classLion:Animal{
publicoverridevoidFeed()//定義子類的虛方法
{
Console.WriteLine("我吃肉.");
}
newpublicvoidFeed2()//定義子類的非虛方法
{
Console.WriteLine("我吃食物.");
}
}
classRabbit:Animal
{
publicoverridevoidFeed()//定義子類的虛方法
{Console.WriteLine("我吃草.");
}
newpublicvoidFeed2()//定義子類的非虛方法
{
Console.WriteLine("我吃食物.");
}
}
classTest
{
publicstaticvoidMain()
{
Animal[]animals=newAnimal[2];
animals[0]=newLion();
animals[1]=newRabbit();Console.WriteLine("---調(diào)用虛方法Feed---");
foreach(Animalanimalinanimals)
{
animal.Feed();
}
Console.WriteLine("---調(diào)用非虛方法Feed2---");
foreach(Animalanimalinanimals)
{
animal.Feed2();
}
}
}
運行結(jié)果如圖6-14所示。圖6-14例6-14運行結(jié)果6.6.1給類成員不合理賦值
【例6-15】給Car不合理賦值的例子。
usingSystem;
classCar
{
publicstringcolor;
publicfloatweight;
publicvoiddisplay()6.6屬性{
Console.WriteLine("顏色是{0},重量為{1}",color,weight);
}
}
classClass1
{
staticvoidMain(string[]args)
{
Carcar=newCar();
car.color="red";
car.weight=-30;//不合理
car.display();
}
}
運行結(jié)果如圖6-15所示。圖6-15例6-15運行結(jié)果6.6.2屬性的定義與使用
1.屬性定義
聲明屬性的語法格式為:
訪問修飾符類型屬性名
{
get
{
… //代碼體
}
set
{
… //代碼體
}
}
2.get和set方法
get訪問函數(shù)是一個不帶參數(shù)的方法,它用于向外部返回屬性成員的值。通常,get訪問函數(shù)中的語句或語句塊主要用return返回某個變量成員的值。get訪問函數(shù)的基本格式如下:
[修飾符]get{訪問體}
set訪問器是一個帶有單個參數(shù)并且返回類型為void類型的方法,它用于處理類外部的寫入值,其中參數(shù)類型就是屬性的類型。它的基本格式為:
[修飾符]set{訪問體}
set訪問函數(shù)有一個特殊的關(guān)鍵字value,value就是set訪問函數(shù)的隱式參數(shù),在set函數(shù)中通過value參數(shù)將外部的輸入傳遞進來,然后賦值給其中的某個變量成員。
在屬性的訪問聲明中,如果只有set訪問器,表明該屬性是只寫的;如果只有g(shù)et訪問器,表明該屬性是只讀的;如果既有set訪問器,又有g(shù)et訪問器,表明該屬性是可讀可
寫的。
3.訪問屬性
訪問對象的屬性(間接調(diào)用get、set)的方式如下:
對象.屬性=值(調(diào)用set)
變量=對象.屬性(調(diào)用get)
【例6-16】用屬性控制不正確的賦值。usingSystem;
classCar
{
privatestringcolor;
privatefloatweight;
publicfloatWeight
{
get{returnweight;}
set
{
if(value<0)
{
Console.WriteLine("重量不能為負(fù)數(shù)!");
}else
{
weight=value;
}
}
}
publicstringColor{get{returncolor;}set{color=value;}}
publicvoiddisplay()
{
Console.WriteLine("我的顏色是{0},我的重量為{1}",color,weight);
}
}
classClass1
{
staticvoidMain(string[]args)
{
Carcar=newCar();
car.Color="red";
car.Weight=-3;
}
}
運行結(jié)果如圖6-16所示。圖6-16例6-16運行結(jié)果程序說明:
當(dāng)運行car.Color=“red”?語句時,程序運行時會自動執(zhí)行set部分,把對象car的私有變量成員color的值賦于red。而當(dāng)運行以下代碼:
Console.WriteLine(“我的顏色是{0},我的重量為{1}”,car.Color,car.Weight);
此時程序自動調(diào)用get訪問函數(shù)獲得對象Color、Weight的屬性。6.6.3索引器
索引器(Indexer)使得對象可以像數(shù)組那樣被引用,為訪問對象中的數(shù)組元素提供了方便、直觀的方法。
索引器的定義格式如下:
[修飾符]類型this[intindex]
{
get
{
… //代碼體
}
set
{
… //代碼體
}
}其中:
●“[修飾符]”同前述。
●“數(shù)據(jù)類型”指的是索引器中的元素類型,可以是C#中的各種數(shù)據(jù)類型。
●?this關(guān)鍵字表示當(dāng)前類的對象。在類的內(nèi)部方法中使用this,就相當(dāng)于將當(dāng)前類的某個對象名稱用this來替代。
●參數(shù)intindex是要訪問元素的索引值。此參數(shù)習(xí)慣上為int型的。
●?{}中的代碼包括get和set部分,其作用同屬性為get和set訪問函數(shù),但兩個函數(shù)沒有返回值和參數(shù)定義。當(dāng)使用索引時,訪問函數(shù)自動被調(diào)用?!纠?-17】訪問數(shù)組成員,但不使用索引器。
usingSystem;
classColors
{
publicstring[]arr={"Red","Yellow","Green","Blue","Black"};
staticvoidMain(string[]args)
{
Colorscolors=newColors();
for(intx=0;x<5;x++)
Console.WriteLine(colors.arr[x]);
}
}
運行結(jié)果如圖6-17所示。圖6-17例6-17運行結(jié)果【例6-18】使用索引器訪問數(shù)組成員。
usingSystem;
classColors
{
privatestring[]arr={"Red","Yellow","Green","Blue","Black"};
publicstringthis[intindex]
{
get{returnarr[index];}
set{arr[index]=value;}
}
staticvoidMain(string[]args)
{
Colorscolors=newColors();
for(intx=0;x<5;x++)
Console.WriteLine(colors[x]);
}
}
運行結(jié)果如圖6-18所示。圖6-18例6-18運行結(jié)果6.6.4抽象類和抽象方法
1.聲明抽象類與抽象方法
聲明抽象類與抽象方法均需使用關(guān)鍵字abstract,其格式為:
publicabstractclass類名稱
{
…
publicabstract返回類型方法名稱(參數(shù)列表);
…
}
2.重載抽象方法
當(dāng)定義抽象類的派生類時,必須重寫(重載)抽象類的抽象方法,這是抽象方法與虛方法的不同,因為對于基類的虛方法,其派生類可以不必重寫(重載)。重載抽象類方法使用override關(guān)鍵字。重載抽象方法的格式為:
pulbicoverride返回類型方法名稱(參數(shù)列表)
{...}
其中,方法名稱與參數(shù)列表必須與抽象類中的抽象方法完全一致。
【例6-19】編寫Animal類及其兩個子類Lion和Rabbit。要求使用抽象方法。
usingSystem;
abstractclassAnimal
{
publicabstractvoidFeed();
}
classLion:Animal
{
publicoverridevoidFeed()
{
System.Console.WriteLine("我吃肉.");
}
}
classRabbit:Animal
{
publicoverridevoidFeed()
{
System.Console.WriteLine("我吃草.");
}
}
classTest
{
publicstaticvoidFeed(Animalanimal)
{
animal.Feed();
}
publicstaticvoidMain()
{
Lionlion=newLion();
Rabbitrabbit=newRabbit();
Feed(lion);
Feed(rabbit);
}
}
運行結(jié)果如圖6-19所示。圖6-19例6-19運行結(jié)果6.6.5接口
1.接口概念
接口(interface)是一組包含了方法的數(shù)據(jù)結(jié)構(gòu),只有聲明部分,沒有實現(xiàn)部分。接口定義一個約定,是對一組能夠提供相同服務(wù)的類的抽象,接口的采用確保了互操作性。
一個設(shè)計良好的接口可以包含一個緊密相關(guān)的功能集合,這些功能定義了一個特定行為,當(dāng)一個對象實現(xiàn)了這個接口時,該對象就實現(xiàn)了這個行為。
與類一樣,接口成員包括方法、屬性、索引器和事件等。
2.接口的聲明
聲明接口時使用interface關(guān)鍵字,定義接口的一般形式為:
[訪問修飾符]interface接口名[:基類接口名]
{
…//接口的成員;
}
接口的名字一般以大寫字母“I”開頭。下面的代碼是C#接口的一個例子:
interfaceIShape
{
voidDraw();
}
如果從兩個或者兩個以上的接口派生,父接口的名字列表用逗號分隔,如下面的代碼所示:
interfaceINewInterface:IParent1,IParent2{}
3.實現(xiàn)接口
接口實現(xiàn)的語句格式為:
class類名:接口名列表
{
… //類實體
}說明:
●當(dāng)一個類實現(xiàn)一個接口時,這個類就必須實現(xiàn)整個接口,而不能選擇實現(xiàn)接口的某一部分。
●一個接口可以由多個類來實現(xiàn),而在一個類中也可以實現(xiàn)一個或多個接口。
●一個類可以繼承一個基類,并同時實現(xiàn)一個或多個接口。
●接口成員的默認(rèn)訪問方式是public,接口成員定義不能包含任何修飾符。
●在類中實現(xiàn)的成員的數(shù)據(jù)類型也必須和它們在接口中聲明的類型完全一樣。
【例6-20】所有動物都有“叫”這一動作,但各動物有自己的叫聲;設(shè)計一個“叫”這一動作的接口,并在其他動物類(如貓、狗)中實現(xiàn)該接口。
usingSystem;
interfaceICry //接口
{
voidCry();
}
classCat:ICry //貓類,實現(xiàn)ICry接口
{
publicvoidCry()
{
Console.WriteLine("喵喵");
}}
classDog:ICry //狗類,實現(xiàn)ICry接口
{
publicvoidCry()
{
Console.WriteLine("汪汪");
}
}
classProgram
{
publicstaticvoidMain()
{
ICryAnimal=newCat();
Animal.Cry();
Animal=newDog();
Animal.Cry();
}
}
運行結(jié)果如圖6-20所示。圖6-20例6-20運行結(jié)果
4.接口與抽象類的比較
接口類似于抽象類,但它與類之間的差別很大:
●抽象類通常提供某些方法和屬性的實現(xiàn)。相反,接口不會描述任何實現(xiàn)。
●接口只包含方法、屬性、事件和索引器,而不包含數(shù)據(jù)成員、構(gòu)造函數(shù)、析構(gòu)函數(shù),也不能包含靜態(tài)成員。
●接口中的所有成員都被視為公有的。
●類可以實現(xiàn)多于一個接口,但只能繼承自一個類。6.7.1變量的作用域
變量的作用域,也叫做變量的生命周期,變量只有在它的生命周期內(nèi)才是有效的,才可以被訪問和使用;超過了生命周期就沒有意義,任何對它的訪問和使用,都會產(chǎn)生程序編譯錯誤。變量的作用域一般是由變量聲明的位置決定的,變量在被定義時開始了生命周期,在被定義時所在的語句塊結(jié)束時生命周期終止。此外,變量的實際作用域還和變量的訪問修飾符密切相關(guān)。6.7知識拓展變量的作用域大致分為以下幾種:靜態(tài)變量作用域、實例變量作用域、方法參數(shù)作用域、局部變量作用域、異常處理參數(shù)作用域。
●靜態(tài)變量作用域:帶有“static”修飾符聲明的成員變量為靜態(tài)成員變量。當(dāng)靜態(tài)成員變量所屬類被裝載后,靜態(tài)成員變量生命周期開始,直到包含該所屬類的程序運行結(jié)束后,靜態(tài)成員變量生命周期結(jié)束。在C#中不存在類似其他語言的全局變量,使用公共靜態(tài)成員變量可以實現(xiàn)類似的效果?!駥嵗兞孔饔糜颍翰粠А皊tatic”修飾符聲明的變量為實例成員變量。當(dāng)一個類的實例被創(chuàng)建,其實例成員變量生命周期開始,直到該實例不再被使用且所占用內(nèi)存空間被釋放,其實例成員變量生命周期結(jié)束。實例成員變量和該類的具體實例具有相同的生命周期。
●方法參數(shù)作用域:方法參數(shù)變量的生命周期只在該方法的語句塊內(nèi)存在,方法被調(diào)用時,生命周期開始,方法執(zhí)行完畢,生命周期結(jié)束?!窬植孔兞孔饔糜颍壕植孔兞吭谄浔欢x的位置生命周期開始,直到該局部變量被定義的語句塊執(zhí)行結(jié)束后生命周期結(jié)束。局部變量在使用時需要程序員手動進行初始化。
●異常處理參數(shù)作用域:異常處理參數(shù)變量的生命周期只在錯誤處理語句塊內(nèi)(即catch語句塊內(nèi))存在。
變量的訪問修飾符限制了變量的可見性,這些修飾符包括public、protected、private、internal和protectedinternal。如果不使用修飾符,默認(rèn)情況下為private?!纠?-21】變量作用域。
usingSystem;
classclass1
{
staticvoiddisplay()
{
Console.WriteLine(str);
}
staticvoidMain(string[]args)
{
stringstr="HelloWorld";
display();
}
}
編譯該段代碼會出現(xiàn)如圖6-21所示的錯誤信息。圖6-21編譯錯誤信息在Main函數(shù)中定義的str變量在函數(shù)display中不能使用的原因在于,變量有其特定的作用域,只有在它所屬的作用域內(nèi),該變量才是有效的。這里所說的作用域包括定義變量的代碼塊和嵌套在該代碼塊中的代碼塊。函數(shù)中的代碼塊與調(diào)用該函數(shù)的代碼塊是分離的,對于該例來說,Main函數(shù)和display函數(shù)就是不同的作用域。因而,在Main函數(shù)中定義的變量str如果在函數(shù)display中使用,就超出了該變量的作用域,str只能在Main函數(shù)中使用,而不能在Main函數(shù)以外使用。
正是因為函數(shù)中的代碼塊與調(diào)用該函數(shù)的代碼塊是分離的,所以可以在Main函數(shù)和display函數(shù)中定義兩個名字完全相同的變量,這兩個變量卻互不干擾,如下面的程序所示?!纠?-22】變量作用域1。
usingSystem;
classclass1
{
staticvoiddisplay()
{
stringstr="你好";
Console.WriteLine(str);
}
staticvoidMain(string[]args)
{
stringstr="HelloWorld";
Console.WriteLine(str);
display();
}
}
運行結(jié)果如圖6-22所示。圖6-22例6-22運行結(jié)果【例6-23】變量的作用域2。
usingSystem;
classProgram
{
staticvoidMain(string[]args)
{
intx; //x可被Main()內(nèi)的所有代碼識別
x=10;
if(x==10)
{//開始新作用域
inty=20; //y只被這個塊識別
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 腳內(nèi)側(cè)運球課程設(shè)計
- 二零二五年度2025版KTV加盟分公司特許經(jīng)營合同2篇
- 知識產(chǎn)權(quán)師培訓(xùn)課程設(shè)計
- 2025年度房地產(chǎn)項目場地租賃管理協(xié)議3篇
- 網(wǎng)絡(luò)傳媒基礎(chǔ)課程設(shè)計
- 2025版新能源汽車充電站建設(shè)工程合同范本(含充電設(shè)備維護)3篇
- 2025版全國聯(lián)動西瓜種植基地銷售合作協(xié)議2篇
- 洗衣機控制設(shè)計課程設(shè)計
- 二零二五年倉儲物流開荒保潔驗收規(guī)范合同3篇
- 水污染控制課程設(shè)計海報
- 國家開放大學(xué)電大??啤缎谭▽W(xué)(1)》題庫及答案
- 行業(yè)代碼大全
- 術(shù)前術(shù)后健康宣教
- 新東方國際游學(xué)報名表
- 數(shù)學(xué)八年級下冊第十七章 小結(jié)與復(fù)習(xí)
- 《哈佛管理制度全集-中文》
- 仁愛版九年級上冊英語中考專題復(fù)習(xí)訓(xùn)練課件
- 部編版四年級語文下冊第5單元大單元整體教學(xué)作業(yè)設(shè)計(教案配套)
- 【超星爾雅學(xué)習(xí)通】【紅色經(jīng)典影片與近現(xiàn)代中國發(fā)展(首都師范大學(xué))】章節(jié)測試及答案
- 市政工程工程開工報審表及開工令
- 2022-2023學(xué)年新疆維吾爾自治區(qū)烏魯木齊市小學(xué)語文四年級上冊期末通關(guān)試卷
評論
0/150
提交評論