• <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>
    • 軟件測試技術
    • 軟件測試博客
    • 軟件測試視頻
    • 開源軟件測試技術
    • 軟件測試論壇
    • 軟件測試沙龍
    • 軟件測試資料下載
    • 軟件測試雜志
    • 軟件測試人才招聘
      暫時沒有公告

    字號: | 推薦給好友 上一篇 | 下一篇

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

    發布: 2007-6-30 18:56 | 作者: admin | 來源: | 查看: 12次 | 進入軟件測試論壇討論

    領測軟件測試網 第五章  類(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();
      基類方法的實現就被調用了。這種行為不同于改寫方法,后者保證大部分派生方法獲得調用。

    文章來源于領測軟件測試網 http://www.kjueaiud.com/


    關于領測軟件測試網 | 領測軟件測試網合作伙伴 | 廣告服務 | 投稿指南 | 聯系我們 | 網站地圖 | 友情鏈接
    版權所有(C) 2003-2010 TestAge(領測軟件測試網)|領測國際科技(北京)有限公司|軟件測試工程師培訓網 All Rights Reserved
    北京市海淀區中關村南大街9號北京理工科技大廈1402室 京ICP備10010545號-5
    技術支持和業務聯系:info@testage.com.cn 電話:010-51297073

    軟件測試 | 領測國際ISTQBISTQB官網TMMiTMMi認證國際軟件測試工程師認證領測軟件測試網

    老湿亚洲永久精品ww47香蕉图片_日韩欧美中文字幕北美法律_国产AV永久无码天堂影院_久久婷婷综合色丁香五月

  • <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>