亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

<展現C#> 第五章 類 (1) 

2019-11-18 22:07:07
字體:
來源:轉載
供稿:網友
第五章  類(1)
       前一章討論了數據類型和它們的用法?,F在我們轉移到C#中至關重要的結構——類。沒有了類,就連簡單的C#程序都不能編譯。這一章假定你知道了一個類的基本組成部分:方法、屬性、構造函數和析構函數。 C#在其中增加了索引和事件。
       在這一章中,你學到下列有關類的話題。
      。 使用構造函數和析構函數
      。給類寫方法
      。給一個類增加屬性存取標志
      。實現索引
      。創建事件并通過代表元為事件關聯客戶
      。應用類、成員和存取修飾符。

5.1  構造函數和析構函數
          在你可以訪問一個類的方法、屬性或任何其它東西之前, 第一條執行的語句是包含有相應類的構造函數。甚至
你自己不寫一個構造函數,也會有一個缺省的構造函數提供給你。

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

       一個構造函數總是和它的類名相同,但是,它沒有聲明返回類型??傊?,構造函數總是public的,你可以用它們來
初始化變量。

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

       如果類僅包含靜態成員(能以類型調用,而不是以實例調用的成員),你可以創建一個PRivate的構造函數。
private TestClass() {}
       盡管存取修飾符在這一章的后面將要大篇幅地討論,但是private意味著從類的外面不可能訪問該構造函數。所
以,它不能被調用,且沒有對象可以自該類定義被實例化。
       并不僅限于無參數構造函數——你可以傳遞初始參數來初始化成員。
       public TestClass(string strName, int nAge) { ... }

       作為一個C/C++程序員,你可能習慣于給初始化寫一個附加的方法,因為在構造函數中沒有返回值。當然,盡管在
C#中也沒有返回值,但你可以引發一個自制的異常,以從構造函數獲得返回值。更多有關異常處理的知識在第七章 "異常
處理"中有討論。
       但是,當你保留引用給寶貴的資源,應該想到寫一個方法來解決:一個可以被顯式地調用來釋放這些資源。問題是
當你可以在析構函數(以類名的前面加"~"的方式命名)中做同樣的事情時,為何還要寫一個附加的方法.
public ~TestClass()
{
// 清除
}

    你應該寫一個附加方法的原因是垃圾收集器,它在變量超出范圍后并不會立即被調用,而僅當間歇期間或內存條件滿
足時才被觸發。當你鎖住資源的時間長于你所計劃的時間時,它就會發生。因此,提供一個顯式的釋放方式是一個好主
意,它同樣能從析構函數中調用。

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

public ~TestClass()
{
Release();
}

    調用析構函數中的釋放方法并不是必要的——總之,垃圾收集會留意釋放對象。但沒有忘記清除是一種良好的習慣。

5.2  方法
     既然對象能正確地初始化和結束,所剩下來的就是往類中增加功能。在大多數情況下,功能的主要部分在方法中能得
到實現。你早已見過靜態方法的使用,但是,這些是類型(類)的部分,不是實例(對象)。
    為了讓你迅速入門,我把這些方法的煩瑣問題安排為三節:
。方法參數
。改寫方法
。方法屏蔽
5.2.1  方法參數
  因方法要處理更改數值,你多多少少要傳遞值給方法,并從方法獲得返回值。以下三個部分涉及到由傳遞值和為調用者
獲取返回結果所引起的問題。

。輸入參數
。引用參數
。輸出參數

5.2.1.1  輸入參數
  你早已在例子中見過的一個參數就是輸入參數。你用一個輸入參數通過值傳遞一個變量給一個方法——方法的變量被調
用者傳遞進來的值的一個拷貝初始化。清單5.1 示范輸入參數的使用。

清單  5.1 通過值傳遞參數

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: }

   因為我傳遞值而不是引用給一個變量,所以當調用方法時(見第16行),可以使用一個常量表達式(25)。整型結果被傳回
給調用者作為返回值,它沒有存到中間變量就被立即顯示到屏幕上 。
    輸入參數按C/C++程序員早已習慣的工作方式工作。如果你來自VB,請注意沒有能被編譯器處理的隱式ByVal或ByRef—
—如果沒有設定,參數總是用值傳遞。
     這點似乎與我前面所陳述的有沖突:對于一些變量類型,用值傳遞實際上意味著用引用傳遞。迷惑嗎? 一點背景知識
也不需要:COM中的東西就是接口,每一個類可以擁有一個或多個接口。一個接口只不過是一組函數指針,它不包含數據。
重復該數組會浪費很多內存資源;所以,僅開始地址被拷貝給方法,它作為調用者,仍然指向接口的相同指針。那就是為
什么對象用值傳遞一個引用。

5.2.1.2  引用參數
    盡管可以利用輸入參數和返回值建立很多方法,但你一想到要傳遞值并原地修改它(也就是在相同的內存位置),就沒
有那么好運了。這里用引用參數就很方便。
void myMethod(ref int nInOut)
   因為你傳遞了一個變量給該方法(不僅僅是它的值),變量必須被初始化。否則,編譯器會報警。清單 5.2 顯示如何用
一個引用參數建立一個方法。

清單 5.2  通過引用傳遞參數

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: }

   正如所看到的,所有你要做的就是給定義和調用都加上ref限定符。因為變量通過引用傳遞,你可以用它來計算出結果
并傳回該結果。但是,在現實的應用程序中,我強烈建議要用兩個變量,一個輸入參數和一個引用參數。

5.2.1.3  輸出參數
   傳遞參數的第三種選擇就是把它設作一個輸出參數。正如該名字所暗示,一個輸出參數僅用于從方法傳遞回一個結果。
它和引用參數的另一個區別在于:調用者不必先初始化變量才調用方法。這顯示在清單5.3中。

清單  5.3  定義一個輸出參數

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  改寫方法
    面向對象設計的重要原則就是多態性。不要理會高深的理論,多態性意味著:當基類程序員已設計好用于改寫的方法
時,在派生類中,你就可以重定義(改寫)基類的方法?;惓绦騿T可以用 virtual 關鍵字設計方法:
virtual void CanBOverridden()
    當從基類派生時,所有你要做的就是在新方法中加入override關鍵字:
override void CanBOverridden()
    當改寫一個基類的方法時,你必須明白,不能改變方法的訪問屬性——在這章的后面,你會學到更多關于訪問修飾符
的知識。
    除了改寫基類方法的事實外,還有另一個甚至更重要的改寫特性。當把派生類強制轉換成基類類型并接著調用虛擬方
法時,被調用的是派生類的方法而不是基類的方法。
((BaseClass)DerivedClassInstance).CanBOverridden();
       為了演示虛擬方法的概念,清單 5.4 顯示如何創建一個三角形基類,它擁有一個可以被改寫的成員方法
(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。它采用三個參數,返回一個double結果,且具有公共訪問性。從Triangle類派
生出的是RightAngledTriangle,它改寫了ComputeArea 方法,并實現了自己的面積計算公式。兩個類都被實例化,且在命
名為TriangleTestApp的應用類的Main() 方法中得到驗證。
我漏了解釋第14行:
class RightAngledTriangle : Triangle
    在類語句中冒號(:)表示RightAngledTriangle從類 Triangle派生。那就是你所必須要做的,以讓C#知道你想把
Triangle當作RightAngledTriangle的基類。
     當仔細觀察直角三角形的ComputeArea方法時,你會發現第3個參數并沒有用于計算。但是,利用該參數就可以驗證是
否是“直角”。如清單5.5所示。

清單 5.5   調用基類實現

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: }

  該檢測簡單地利用了畢達哥拉斯公式,對于直角三角形,檢測結果必須為0。如果結果不為0,類就調用它基類的
ComputeArea來實現。
dArea = base.ComputeArea(a,b,c);
  例子的要點為:通過顯式地利用基類的資格檢查,你就能輕而易舉地調用基類實現改寫方法。
當你需要實現其在基類中的功能,而不愿意在改寫方法中重復它時,這就非常有幫助。

5.2.3 方法屏蔽
    重定義方法的一個不同手段就是要屏蔽基類的方法。當從別人提供的類派生類時,這個功能特別有價值??辞鍐?
5.6,假設BaseClass由其他人所寫,而你從它派生出 DerivedClass 。

清單 5.6   Derived Class 實現一個沒有包含于 Base Class中的方法

1: using System;
2:
3: class BaseClass
4: {
5: }
6:
7: class DerivedClass:BaseClass
8: {
9:  public void TestMethod()
10:  {
11:   Console.WriteLine("DerivedClass::TestMethod");
12:  }
13: }
14:
15: class TestApp
16: {
17:  public static void Main()
18:  {
19:   DerivedClass test = new DerivedClass();
20:   test.TestMethod();
21:  }
22: }

    在這個例子中, DerivedClass 通過TestMethod()實現了一個額外的功能。但是,如果基類的開發者認為把
TestMethod()放在基類中是個好主意,并使用相同的名字實現它時,會出現什么問題呢?(見清單5.7)

清單 5.7    Base Class 實現和 Derived Class相同的方法

1: class BaseClass
2: {
3:  public void TestMethod()
4:  {
5:   Console.WriteLine("BaseClass::TestMethod");
6:  }
7: }
8:
9: class DerivedClass:BaseClass
10: {
11:  public void TestMethod()
12:  {
13:   Console.WriteLine("DerivedClass::TestMethod");
14:  }
15: }

在優秀的編程語言中,你現在會遇到一個真正的大麻煩。但是,C#會給你提出警告:
hiding2.cs(13,14): warning CS0114: 'DerivedClass.TestMethod()' hides inherited member 'BaseClass.TestMethod
()'. To make the current method override that implementation, add the override keyWord. Otherwise add the
new keyword.
(hiding2.cs(13,14):警告  CS0114:'DerivedClass.TestMethod()' 屏蔽了所繼承的成員'BaseClass.TestMethod()'。要
想使當前方法改寫原來的實現,加上 override關鍵字。否則加上新的關鍵字。)
具有了修飾符new,你就可以告訴編譯器,不必重寫派生類或改變使用到派生類的代碼,你的方法就能屏蔽新加入的基類方
法。清單5.8  顯示如何在例子中運用new修飾符。

清單  5.8   屏蔽基類方法

1: class BaseClass
2: {
3:  public void TestMethod()
4:  {
5:   Console.WriteLine("BaseClass::TestMethod");
6:  }
7: }
8:
9: class DerivedClass:BaseClass
10: {
11:  new public void TestMethod()
12:  {
13:   Console.WriteLine("DerivedClass::TestMethod");
14:  }
15: }

使用了附加的new修飾符,編譯器就知道你重定義了基類的方法,它應該屏蔽基類方法。但是,如果你按以下方式編寫:
DerivedClass test = new DerivedClass();
((BaseClass)test).TestMethod();
  基類方法的實現就被調用了。這種行為不同于改寫方法,后者保證大部分派生方法獲得調用。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲美女www午夜| 精品亚洲一区二区三区| 午夜精品理论片| 久久精品视频免费播放| 国产精品国产亚洲伊人久久| 日韩av网站在线| 欧美日韩国产中字| 成人免费网站在线| 91久久精品美女高潮| 欧美在线日韩在线| 精品女同一区二区三区在线播放| 欧美性资源免费| 伊人亚洲福利一区二区三区| 日韩69视频在线观看| 成人亲热视频网站| 国产精品女人久久久久久| 欧美日韩在线观看视频小说| 亚洲r级在线观看| 日韩电影网在线| 国产精品网站视频| 欧美日韩aaaa| 日韩av在线播放资源| 在线观看国产成人av片| 日韩精品免费在线视频观看| 国产精品精品久久久| 精品夜色国产国偷在线| 韩日精品中文字幕| 国产精品日韩精品| 欧美日韩国产成人在线| 91精品久久久久久久久| 久久国产精品久久国产精品| 成人黄色影片在线| 日本久久久久久久久久久| 亚洲一区二区久久久| 欧美日韩另类视频| xvideos亚洲| 色爱av美腿丝袜综合粉嫩av| 国产美女主播一区| 国产综合久久久久| 亚洲成人精品av| 日韩av在线影院| 成人国产精品日本在线| 日韩欧美国产网站| 日韩在线视频国产| 日韩精品视频免费在线观看| 日韩美女视频免费看| 一区二区三区精品99久久| 色播久久人人爽人人爽人人片视av| 久久五月天色综合| 日韩精品免费观看| 91精品国产自产91精品| 亚洲男人天堂久| 国外成人性视频| 国产不卡av在线| 韩剧1988免费观看全集| 亚洲片在线观看| 另类美女黄大片| 国产精品免费一区豆花| 免费av一区二区| 久久久国产精品亚洲一区| 亚洲一区二区三区777| 精品视频www| 伦伦影院午夜日韩欧美限制| 成人免费看黄网站| 97视频人免费观看| 精品欧美一区二区三区| 精品女同一区二区三区在线播放| 538国产精品一区二区在线| 久久人人爽人人爽爽久久| 国产视频精品一区二区三区| 日本精品一区二区三区在线播放视频| 亚洲人成电影网站色www| 日韩高清电影好看的电视剧电影| 亚洲欧美中文日韩在线v日本| 午夜精品久久久久久久99热浪潮| 欧美日韩在线影院| 亚洲人成亚洲人成在线观看| 亚洲一区二区三区香蕉| 精品成人在线视频| 欧美一级淫片丝袜脚交| 欧美成人精品h版在线观看| 欧美日韩国产va另类| 尤物yw午夜国产精品视频| 一区二区三区久久精品| 亚洲成在人线av| 成人国产精品久久久| 国产91色在线免费| 亚洲自拍偷拍色片视频| www日韩中文字幕在线看| 这里只有视频精品| 日本精品va在线观看| 亚洲精品免费网站| 久久久噜噜噜久久久| 欧洲成人在线视频| 欧美成人精品在线观看| 欧美性猛交xxxx富婆弯腰| 国产丝袜一区视频在线观看| 精品无人区太爽高潮在线播放| 97色在线播放视频| 日韩精品在线电影| 亚洲天堂网在线观看| 国产精品99一区| 欧美激情欧美激情在线五月| 国产视频精品免费播放| 蜜臀久久99精品久久久无需会员| 日韩av网站电影| 亚洲成人精品久久久| 亚洲自拍高清视频网站| 精品福利免费观看| 国产精品网红直播| 欧美亚洲一区在线| 久久精品国产亚洲一区二区| 久久精品国产亚洲| 久久久亚洲成人| 久久久久免费精品国产| 久久99国产综合精品女同| 欧美一区二区三区精品电影| 国产乱人伦真实精品视频| 日本精品免费一区二区三区| 欧美亚洲第一区| 在线看福利67194| 欧美精品18videosex性欧美| 日韩电影中文字幕在线| 国产精品久久久久77777| 97碰在线观看| 亚洲成人网久久久| 91精品久久久久久久久不口人| 97精品视频在线播放| 欧美亚洲日本网站| 国产偷国产偷亚洲清高网站| 国产精品对白刺激| 91精品国产高清久久久久久91| 91精品国产91久久| 国产精品91视频| 日韩国产高清视频在线| 欧美精品在线观看| 国产精品美女主播| 国产精品美女www爽爽爽视频| 国产精品午夜国产小视频| 久久久精品国产一区二区| 欧美成人免费播放| 国产日韩欧美中文在线播放| 欧美肥老妇视频| 亚洲欧美另类自拍| 一区二区av在线| 国产69精品久久久久久| 国产日韩精品在线播放| 欧美日韩免费网站| 亚洲在线免费观看| 5252色成人免费视频| 91精品视频大全| 亚洲国产美女精品久久久久∴| 国产欧美久久一区二区| 成人性生交xxxxx网站| 亚洲国产欧美一区二区三区久久| 国产热re99久久6国产精品| 国产成人精品综合| 中文字幕亚洲国产| 日韩av一卡二卡| 亚洲欧美激情精品一区二区| 国产91精品久久久久| 日韩在线观看免费av| 欧美日韩国产一中文字不卡| 伊人伊人伊人久久|