国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > .NET > 正文

《.net編程先鋒C#》第五章 類(轉(zhuǎn))

2024-07-10 13:02:18
字體:
供稿:網(wǎng)友

第五章 類
前一章討論了數(shù)據(jù)類型和它們的用法?,F(xiàn)在我們轉(zhuǎn)移到c#中至關(guān)重要的結(jié)構(gòu)——類。沒有了
類,就連簡單的c#程序都不能編譯。這一章假定你知道了一個類的基本組成部分:方法、屬性、構(gòu)

造函數(shù)和析構(gòu)函數(shù)。 c#在其中增加了索引和事件。
在這一章中,你學(xué)到下列有關(guān)類的話題。
。 使用構(gòu)造函數(shù)和析構(gòu)函數(shù)
。給類寫方法
。給一個類增加屬性存取標(biāo)志
。實現(xiàn)索引
。創(chuàng)建事件并通過代表元為事件關(guān)聯(lián)客戶
。應(yīng)用類、成員和存取修飾符。

5.1 構(gòu)造函數(shù)和析構(gòu)函數(shù)
在你可以訪問一個類的方法、屬性或任何其它東西之前, 第一條執(zhí)行的語句是包含有相

應(yīng)類的構(gòu)造函數(shù)。甚至你自己不寫一個構(gòu)造函數(shù),也會有一個缺省的構(gòu)造函數(shù)提供給你。

class testclass
{
public testclass(): base() {} // 由編譯器提供
}

一個構(gòu)造函數(shù)總是和它的類名相同,但是,它沒有聲明返回類型??傊?,構(gòu)造函數(shù)總是

public的,你可以用它們來初始化變量。

public testclass()
{
// 在這給變量
// 初始化代碼等等。
}

如果類僅包含靜態(tài)成員(能以類型調(diào)用,而不是以實例調(diào)用的成員),你可以創(chuàng)建一個

private的構(gòu)造函數(shù)。
private testclass() {}
盡管存取修飾符在這一章的后面將要大篇幅地討論,但是private意味著從類的外面不可能

訪問該構(gòu)造函數(shù)。所以,它不能被調(diào)用,且沒有對象可以自該類定義被實例化。
并不僅限于無參數(shù)構(gòu)造函數(shù)——你可以傳遞初始參數(shù)來初始化成員。
public testclass(string strname, int nage) { ... }

作為一個c/c++程序員,你可能習(xí)慣于給初始化寫一個附加的方法,因為在構(gòu)造函數(shù)中沒有

返回值。當(dāng)然,盡管在c#中也沒有返回值,但你可以引發(fā)一個自制的異常,以從構(gòu)造函數(shù)獲得返回

值。更多有關(guān)異常處理的知識在第七章 "異常處理"中有討論。
但是,當(dāng)你保留引用給寶貴的資源,應(yīng)該想到寫一個方法來解決:一個可以被顯式地調(diào)用來

釋放這些資源。問題是當(dāng)你可以在析構(gòu)函數(shù)(以類名的前面加"~"的方式命名)中做同樣的事情時,為

何還要寫一個附加的方法.
public ~testclass()
{
// 清除
}

你應(yīng)該寫一個附加方法的原因是垃圾收集器,它在變量超出范圍后并不會立即被調(diào)用,而僅當(dāng)

間歇期間或內(nèi)存條件滿足時才被觸發(fā)。當(dāng)你鎖住資源的時間長于你所計劃的時間時,它就會發(fā)生。

因此,提供一個顯式的釋放方式是一個好主意,它同樣能從析構(gòu)函數(shù)中調(diào)用。

public void release()
{
// 釋放所有寶貴的資源
}

public ~testclass()
{
release();
}

調(diào)用析構(gòu)函數(shù)中的釋放方法并不是必要的——總之,垃圾收集會留意釋放對象。但沒有忘記清

除是一種良好的習(xí)慣。

5.2 方法
既然對象能正確地初始化和結(jié)束,所剩下來的就是往類中增加功能。在大多數(shù)情況下,功能的

主要部分在方法中能得到實現(xiàn)。你早已見過靜態(tài)方法的使用,但是,這些是類型(類)的部分,不是

實例(對象)。
為了讓你迅速入門,我把這些方法的煩瑣問題安排為三節(jié):
。方法參數(shù)
。改寫方法
。方法屏蔽
5.2.1 方法參數(shù)
因方法要處理更改數(shù)值,你多多少少要傳遞值給方法,并從方法獲得返回值。以下三個部分涉及

到由傳遞值和為調(diào)用者獲取返回結(jié)果所引起的問題。

。輸入?yún)?shù)
。引用參數(shù)
。輸出參數(shù)

5.2.1.1 輸入?yún)?shù)
你早已在例子中見過的一個參數(shù)就是輸入?yún)?shù)。你用一個輸入?yún)?shù)通過值傳遞一個變量給一個方

法——方法的變量被調(diào)用者傳遞進(jìn)來的值的一個拷貝初始化。清單5.1 示范輸入?yún)?shù)的使用。

清單 5.1 通過值傳遞參數(shù)

1: using system;
2:
3: public class squaresample
4: {
5: public int calcsquare(int nsidelength)
6: {
7: return nsidelength*nsidelength;
8: }
9: }
10:
11: class squareapp
12: {
13: public static void main()
14: {
15: squaresample sq = new squaresample();
16: console.writeline(sq.calcsquare(25).tostring());
17: }
18: }

因為我傳遞值而不是引用給一個變量,所以當(dāng)調(diào)用方法時(見第16行),可以使用一個常量表達(dá)式

(25)。整型結(jié)果被傳回給調(diào)用者作為返回值,它沒有存到中間變量就被立即顯示到屏幕上 。
輸入?yún)?shù)按c/c++程序員早已習(xí)慣的工作方式工作。如果你來自vb,請注意沒有能被編譯器處理

的隱式byval或byref——如果沒有設(shè)定,參數(shù)總是用值傳遞。
這點似乎與我前面所陳述的有沖突:對于一些變量類型,用值傳遞實際上意味著用引用傳遞。

迷惑嗎? 一點背景知識也不需要:com中的東西就是接口,每一個類可以擁有一個或多個接口。一個

接口只不過是一組函數(shù)指針,它不包含數(shù)據(jù)。重復(fù)該數(shù)組會浪費很多內(nèi)存資源;所以,僅開始地址

被拷貝給方法,它作為調(diào)用者,仍然指向接口的相同指針。那就是為什么對象用值傳遞一個引用。

5.2.1.2 引用參數(shù)
盡管可以利用輸入?yún)?shù)和返回值建立很多方法,但你一想到要傳遞值并原地修改它(也就是在相

同的內(nèi)存位置),就沒有那么好運了。這里用引用參數(shù)就很方便。
void mymethod(ref int ninout)
因為你傳遞了一個變量給該方法(不僅僅是它的值),變量必須被初始化。否則,編譯器會報警。

清單 5.2 顯示如何用一個引用參數(shù)建立一個方法。

清單 5.2 通過引用傳遞參數(shù)

1: // class squaresample
2: using system;
3:
4: public class squaresample
5: {
6: public void calcsquare(ref int none4all)
7: {
8: none4all *= none4all;
9: }
10: }
11:
12: class squareapp
13: {
14: public static void main()
15: {
16: squaresample sq = new squaresample();
17:
18: int nsquaredref = 20; // 一定要初始化
19: sq.calcsquare(ref nsquaredref);
20: console.writeline(nsquaredref.tostring());
21: }
22: }

正如所看到的,所有你要做的就是給定義和調(diào)用都加上ref限定符。因為變量通過引用傳遞,你

可以用它來計算出結(jié)果并傳回該結(jié)果。但是,在現(xiàn)實的應(yīng)用程序中,我強(qiáng)烈建議要用兩個變量,一

個輸入?yún)?shù)和一個引用參數(shù)。

5.2.1.3 輸出參數(shù)
傳遞參數(shù)的第三種選擇就是把它設(shè)作一個輸出參數(shù)。正如該名字所暗示,一個輸出參數(shù)僅用于從

方法傳遞回一個結(jié)果。它和引用參數(shù)的另一個區(qū)別在于:調(diào)用者不必先初始化變量才調(diào)用方法。這

顯示在清單5.3中。

清單 5.3 定義一個輸出參數(shù)

1: using system;
2:
3: public class squaresample
4: {
5: public void calcsquare(int nsidelength, out int nsquared)
6: {
7: nsquared = nsidelength * nsidelength;
8: }
9: }
10:
11: class squareapp
12: {
13: public static void main()
14: {
15: squaresample sq = new squaresample();
16:
17: int nsquared; // 不必初始化
18: sq.calcsquare(15, out nsquared);
19: console.writeline(nsquared.tostring());
20: }
21: }


5.2.2 改寫方法
面向?qū)ο笤O(shè)計的重要原則就是多態(tài)性。不要理會高深的理論,多態(tài)性意味著:當(dāng)基類程序員已

設(shè)計好用于改寫的方法時,在派生類中,你就可以重定義(改寫)基類的方法?;惓绦騿T可以用

virtual 關(guān)鍵字設(shè)計方法:
virtual void canboverridden()
當(dāng)從基類派生時,所有你要做的就是在新方法中加入override關(guān)鍵字:
override void canboverridden()
當(dāng)改寫一個基類的方法時,你必須明白,不能改變方法的訪問屬性——在這章的后面,你會學(xué)

到更多關(guān)于訪問修飾符的知識。
除了改寫基類方法的事實外,還有另一個甚至更重要的改寫特性。當(dāng)把派生類強(qiáng)制轉(zhuǎn)換成基類

類型并接著調(diào)用虛擬方法時,被調(diào)用的是派生類的方法而不是基類的方法。
((baseclass)derivedclassinstance).canboverridden();
為了演示虛擬方法的概念,清單 5.4 顯示如何創(chuàng)建一個三角形基類,它擁有一個可以被改

寫的成員方法(computearea)。

清單 5.4 改寫一個基類的方法

1: using system;
2:
3: class triangle
4: {
5: public virtual double computearea(int a, int b, int c)
6: {
7: // heronian formula
8: double s = (a + b + c) / 2.0;
9: double darea = math.sqrt(s*(s-a)*(s-b)*(s-c));
10: return darea;
11: }
12: }
13:
14: class rightangledtriangle:triangle
15: {
16: public override double computearea(int a, int b, int c)
17: {
18: double darea = a*b/2.0;
19: return darea;
20: }
21: }
22:
23: class triangletestapp
24: {
25: public static void main()
26: {
27: triangle tri = new triangle();
28: console.writeline(tri.computearea(2, 5, 6));
29:
30: rightangledtriangle rat = new rightangledtriangle();
31: console.writeline(rat.computearea(3, 4, 5));
32: }
33: }

基類triangle定義了方法computearea。它采用三個參數(shù),返回一個double結(jié)果,且具有公共訪

問性。從triangle類派生出的是rightangledtriangle,它改寫了computearea 方法,并實現(xiàn)了自己

的面積計算公式。兩個類都被實例化,且在命名為triangletestapp的應(yīng)用類的main() 方法中得到

驗證。
我漏了解釋第14行:
class rightangledtriangle : triangle
在類語句中冒號(:)表示rightangledtriangle從類 triangle派生。那就是你所必須要做的

,以讓c#知道你想把 triangle當(dāng)作rightangledtriangle的基類。
當(dāng)仔細(xì)觀察直角三角形的computearea方法時,你會發(fā)現(xiàn)第3個參數(shù)并沒有用于計算。但是,利

用該參數(shù)就可以驗證是否是“直角”。如清單5.5所示。

清單 5.5 調(diào)用基類實現(xiàn)

1: class rightangledtriangle:triangle
2: {
3: public override double computearea(int a, int b, int c)
4: {
5: const double depsilon = 0.0001;
6: double darea = 0;
7: if (math.abs((a*a + b*b - c*c)) > depsilon)
8: {
9: darea = base.computearea(a,b,c);
10: }
11: else
12: {
13: darea = a*b/2.0;
14: }
15:
16: return darea;
17: }
18: }

該檢測簡單地利用了畢達(dá)哥拉斯公式,對于直角三角形,檢測結(jié)果必須為0。如果結(jié)果不為0,類

就調(diào)用它基類的 computearea來實現(xiàn)。
darea = base.computearea(a,b,c);
例子的要點為:通過顯式地利用基類的資格檢查,你就能輕而易舉地調(diào)用基類實現(xiàn)改寫方法。
當(dāng)你需要實現(xiàn)其在基類中的功能,而不愿意在改寫方法中重復(fù)它時,這就非常有幫助。 
發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 博爱县| 十堰市| 岐山县| 读书| 伊春市| 陆河县| 乌苏市| 泽普县| 清涧县| 崇礼县| 河南省| 合江县| 陆良县| 乐东| 兴文县| 望谟县| 双流县| 大渡口区| 许昌县| 赤壁市| 砀山县| 新闻| 清流县| 吉隆县| 榆树市| 临朐县| 和静县| 阿鲁科尔沁旗| 永仁县| 彰化市| 呼伦贝尔市| 南部县| 额敏县| 海淀区| 无极县| 焉耆| 荔波县| 都昌县| 仲巴县| 长治县| 嘉祥县|