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(stringvalue) { 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中找到該標題
成員的訪問修飾符
對類的可訪問性,只有兩種修飾符:internal和Public
抽象成員
抽象成員指設計為被覆寫的函式成員。抽象成員有以下特徵
- 必須是一個函式成員,即欄位和常量不能是抽象成員
- 必須用abstract修飾
- 不能有實現程式碼塊。程式碼用分號表示
- 共有4個型別的成員可以宣告為抽象:方法、屬性、事件、索引
例:抽象方法和抽象屬性
abstract public void PrintStuff(string s); abstract public int MyProperty { get; set; }
關於抽象成員的注意事項:
- 儘管抽象成員必須在派生類中被覆寫,但不能把virtual和abstract合用
- 類似虛成員,派生類中抽象成員的實現必須指定override修飾符
抽象類
抽象類指設計為被繼承的類。抽象類只能被用作其他類的基類。
- 不能建立抽象類的例項
- 抽象類使用abstract標識
- 抽象類可以包含抽象成員和普通的非抽象成員。
- 抽象類可以派生自另一個抽象類。
- 任何派生自抽象類的類必須使用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()); } } }