1. 程式人生 > 其它 >c#圖解教程_第六章_類和繼承

c#圖解教程_第六章_類和繼承

類繼承


定義:使用已存在的類作為新類的基礎

已存在的類稱之為基類(base class) 新類稱之為派生類(derived class)

派生類成員:

  • 本身宣告的成員
  • 基類的成員

要宣告一個派生類,需要在類名後面加入基類規格說明。基類規格說明由冒號和後面跟著用做基類的類名稱組成,派生類被描述為直接繼承自列出的基類

派生類擴充套件它的基類,因為他包含了基類的成員,加上在它本身宣告中新增的功能

派生類不能刪除它所繼承的任務類成員

                           基類
                             ↓
Class class OtherClass 
: SomeClass{}

訪問繼承的成員


class SomeClass
{
    public string Field1="base class field ";
    public void Method1(string value)
    {
        Console.WriteLine("Base class -- Method1: {0}",value);
    }
}
class OtherClass:SomeClass
{
    public string Field2="derived class field";
    public void Method2(string
value) { Console.WriteLine("Derived class -- Method2: {0}",value); } } class Program { static void Main() { var oc=new OtherClass(); oc.Method1(oc.Field1); //以基類欄位為引數的基類方法 oc.Method1(oc.Field2); //以派生欄位為引數的基類方法 oc.Method2(oc.Field1); //以基類欄位為引數的派生方法
oc.Method2(oc.Field2); //以派生欄位為引數的派生方法 } }

所有類的派生自Object類


一個類宣告的基類規格說明中只能由一個單獨的類,稱之為單繼承

只允許直接繼承一個類,但是繼承的層次沒有影響,可以不斷疊加繼承類的層次

class A{}

class B:A{}

class C:B{}

遮蔽基類的成員


雖然派生類不能刪除它繼承的任何成員,但可以用與基類同名的成員來遮蔽(mask)基類成員。這是繼承的主要功能之一,非常實用。

  • 要遮蔽一個繼承的資料成員,需要宣告一個新的同類型成員,並使用相同名稱
  • 通過在派生類中宣告新的帶有相同簽名的函式成員,可以隱藏或遮蔽繼承的函式成員。(請記住,簽名由名稱和引數列表組成,不包括返回型別)
  • 要讓編譯器知道你在故意遮蔽繼承的成員,使用new修飾符。否則,程式可以成功編譯,但編譯器會警告你隱藏了一個繼承的成員
  • 可遮蔽靜態成員

使用new關鍵字遮蔽基類成員
,替代基類上的同名成員,呼叫該類使用新的方法欄位或方法。

基類的訪問


使用關鍵字Base

class SomeClass
{
    public string Field1="Field1 -- In the base class";
}
class OtherClass:SomeClass
{
    new public string Field1="Field1 -- In the derived class";
    public void PrintField1()
    {
        Console.WriteLine(Field1);
        Console.WriteLine(base.Field1);
    }
}
class Program
{
    static void Main()
    {
        var oc=new OtherClass();
        oc.PrintField1();
    //輸出結果 →
      Field1 -- In the derived class
Field1 -- In the base class
} }

使用基類的引用

MyDerivedClass derived=new MyDerivedClass(); //例項化派生類
MyBaseClass mybc=(MyBaseClass)derived;  //顯示轉換為基類,轉換引用

虛方法和覆寫方法


class MyBaseClass
{
    virtual public void Print()  //關鍵字virtual,虛方法
    ...
}
class MyDerivedClass:MyBaseCLass
{
    override public void Print() //關鍵字Override,重寫虛方法,覆寫
    ...
}

覆寫方法可以在繼承的任何層次出現

當使用物件基類部分的引用呼叫一個覆寫的方法時,方法的呼叫被沿派生層次上溯執行,一直到標記為override的方法的最高派生(most-derived)版本

如果在更高的派生級別有該方法的其他宣告,但沒有被標記為override,那麼它們不會被呼叫

使用new 關鍵字呼叫方法 ,使用new方法的類呼叫的方法必是本身已被new的方法,而不是繼承層次中最高層次的override的方法

class SecondDerived:MyDerivedClass
{
    new public void Print()
    {
        Console.WriteLine("This is the second derived class");
    }
}
class Program
{
    static void Main()
    {
        var derived=new SecondDerived();
        mybc=(MyBaseClass)derived;
        derived.Print();
        mybc.Print();  //輸出結果 → This is the second derived class , This is the derived class
    }
}

覆蓋其他成員型別


派生類中具有同名欄位,當將派生類轉成基類時,基類呼叫的欄位是派生類的欄位值。

class MyBaseClass
{
    private int _myInt=5;
    virtual public int MyProperty
    {
        get{return _myInt;}
    }
}
class MyDerivedClass:MyBaseClass
{
    private int _myInt=10;
    override public int MyProperty
    {
        get{return _myInt;}
    }
}
class Program
{
    static void Main()
    {
        var derived=new MyDerivedClass();
        var mybc=(MyBaseClass)derived;
        Console.WriteLine(derived.MyProperty);  //輸出結果:10
        Console.WriteLine(mybc.MyProperty);  //輸出結果:10
    }
}

類訪問修飾符


類的可訪問性有兩個級別:public和internal

  • 標記為public的類可以被系統內任何程式集中的程式碼訪問
  • 標記為internal的類只能被它自己所在的程式集內的類看到

下圖闡明瞭internal和public類從程式集外部的可訪問性。類MyClass對左邊程式集內的類不可見,因為MyClass被標記為internal。然而,類OtherClass對於左邊的類可見,因為它是public。

程式間的繼承


c#也允許從一個在不同的程式集內定義的基類來派生類

在不同程式集之間繼承,需要滿足兩個條件:

  • 基類必須是public,這樣才能從它所在的程式集外部訪問它
  • 必須在Visual Studio工程中的References節點中新增包含對該基類的程式集的引用,可以在Solution Explorer中找到該標題

成員的訪問修飾符


對類的可訪問性,只有兩種修飾符:internalPublic

抽象成員


抽象成員指設計為被覆寫的函式成員。抽象成員有以下特徵

  • 必須是一個函式成員,即欄位和常量不能是抽象成員
  • 必須用abstract修飾
  • 不能有實現程式碼塊。程式碼用分號表示
  • 共有4個型別的成員可以宣告為抽象:方法、屬性、事件、索引

例:抽象方法和抽象屬性

abstract public void PrintStuff(string s);
abstract public int MyProperty
{
    get;
    set;
}

關於抽象成員的注意事項:

  • 儘管抽象成員必須在派生類中被覆寫,但不能把virtual和abstract合用
  • 類似虛成員,派生類中抽象成員的實現必須指定override修飾符

抽象類


抽象類指設計為被繼承的類。抽象類只能被用作其他類的基類。

  1. 不能建立抽象類的例項
  2. 抽象類使用abstract標識
  3. 抽象類可以包含抽象成員和普通的非抽象成員
  4. 抽象類可以派生自另一個抽象類。
  5. 任何派生自抽象類的類必須使用override關鍵字實現該類所有的抽象成員,除非派生類自己也是抽象類

抽象類和抽象方法示例

abstract class AbClass
{
    public void IdentifyBase()
    {
        Console.WriteLine("I am AbClass");
    }
    abstract public void IndetifyDerived();
}
class DerivedClass:AbClass
{
    override public void IdentifyDerived()
    {
        Console.WriteLine("I am DerivedClass";
    }
}
class Program
{
    static void Main()
    {
        // AbClass a=new AbClass(); ->抽象類不能夠被例項化
        var b=new DerivedClass();
        b.IdentifyBase();         -> 輸出結果:I am AbClass
        b.IdentifyDerived();      -> 輸出結果 I  am DericedClass
    }
}

抽象類的另一個例子

例:包含資料成員和函型別成員的抽象類

abstract class MyBase
{
    public int SideLength=10;
    const int TriangleSideCount=3;
    abstract public void PrintStuff(string s);
    abstract public int MyInt{get;set;}
    public int PerimeterLength()
    {
        return TriangleSideCount*SideLength;
    }
}
class MyCLass:MyBase
{
    public override void PrintStuff(string s)
    {
        Console.WriteLine(s);
    }
    private int _myInt;
    public override int MyInt
    {
        get{return _myINt;}
        set{_myInt=value;}
    }
}
class Program
{
    static void Main()
    {
        var mc=new MyClass();
        mc.PrintStuff("This is a string.");
        mc.MyInt=28;
        Console.WriteLine(mc.MyInt);
        Console.WriteLine("Perimeter Length:{0}",mc.PerimeterLength());
    }
}

密封類


抽象類必須用作基類,它不能被例項化。
密封類與抽象類相反。

  • 密封類只能被用作獨立的類,不能用作基類(被繼承)
  • 密封類使用sealed修飾符標註
sealed class Myclass{}

靜態類


靜態類中所有成員都是靜態的。靜態類用於存放不受例項資料影響的資料和函式。靜態類常見用途就是建立一個包含一組數學方法和值的數學庫。

  • 靜態類本身必須標記為static
  • 類的所有成員必須是靜態的
  • 類可以用一個靜態建構函式,但不能有例項建構函式,不能建立該類的例項
  • 靜態類是隱式密封的,即不能繼承靜態類
sealed class MyClass{}

靜態類

static public class MyMath
{
    public static float PI=3.14f;
    public static bool IsOdd(intx)
    {
        return x%2==1;
    }
    public static int Times2(int x)
    {
        return 2*x;
    }
}
class Program
{
    static void Main()
    {
        int val=3;
        Console.WriteLine("{0} is odd is {1}",val,MyMath.IsOdd(val));  ->類名.靜態成員
        Console.WriteLine("{0} * 2 = {1}",val,MyMath.Time2(val));
    }
}

擴充套件方法


擴充套件方法允許編寫的方法和宣告它的類之外的類關聯。
擴充套件方法的重要要求如下:

  • 宣告擴充套件方法的類必須宣告為static
  • 擴充套件方法本身必須宣告為static
  • 擴充套件方法必須包含關鍵字this作為它的第一個引數型別,並在後面跟著它所擴充套件的類的名稱

例:擴充套件方法示例

namespace ExtensionMethods
{
    sealed class MyData
    {
        private double D1,D2,D3;
        public MyData(double d1,double d2,double d3)
        {
            D1=d1;D2=d2;D3=d3;
        }
        public double Sum()
        {
            return D1+D2+D3;
        }
    }
    static class ExtendMyData
    {
        public static double Average(this MyData md)
        {
            return md.Sum()/3;
        }
    }
    class Program
    {
        static void Main()
        {
            var md=new MyData(3,4,5);
            Console.WriteLine("Sum: {0}",md.Sum());
            Console.WriteLine("Average: {0}",md.Average());
        }
    }
}

命名約定