四、多級繼承
一些面向對象語言允許一個類從多個基類中繼承,而另一些面向對象語言只允許從一個類繼承,但可以隨意從幾個接口或純抽象類中繼承。
只有C++支持多級繼承,許多程序員對此褒貶不一。多級繼承常會引起繼承來的類之間的混亂,繼承而來的方法往往沒有唯一性,所以C#中類的繼承只可以是一個,即子類只能派生于一個父類,而有時你必須繼承多個類的特性,為了實現多重繼承必須使用接口技術,下面是對接口的多重繼承進行介紹:
using System ; //定義一個描述點的接口 interface IPoint { int x { get ; set ; } int y { get ; set ; } } interface IPoint2 { int y { get ; set ; } } //在point中繼承了兩個父類接口,并分別使用了兩個父類接口的方法 class Point:IPoint,IPoint2 { //定義兩個類內部訪問的私有成員變量 private int pX ; private int pY ; public Point(int x,int y) { pX=x ; pY=y ; } //定義的屬性,IPoint接口方法實現 public int x { get { return pX ; } set { pX =value ; } } //IPoint1接口方法實現 public int y { get { return pY ; } set { pY =value ; } } } class Test { private static void OutPut( IPoint p ) { Console.WriteLine("x={0},y={1}",p.x,p.y) ; } public static void Main( ) { Point p =new Point(15,30) ; Console.Write("The New Point is:") ; OutPut( p ) ; string myName =Console.ReadLine( ) ; Console.Write("my name is {0}", myName) ; } } 五、繼承與訪問修飾符
訪問修飾符是一些關鍵字,用于指定聲明的成員或類型的可訪問性。類的繼承中有四個訪問修飾符: public protected internal private。使用這些訪問修飾符可指定下列五個可訪問性級別: public protected internal internal protected private。
聲明的可訪問性 意義 public 訪問不受限制。 protected 訪問僅限于包含類或從包含類派生的類型。 internal 訪問僅限于當前項目。 protected internal 訪問僅限于從包含類派生的當前項目或類型。 private 訪問僅限于包含類型。
1、繼承中關于可訪問域的一些問題
基類的所有成員(實例構造函數、析構函數和靜態構造函數除外)都由派生類型繼承。這甚至包括基類的私有成員。但是,私有成員的可訪問域只包括聲明該成員的類型的程序文本。在下面的示例中
class A { int x ; static void F(B b) { b.x = 1 ; // 對 } } class B: A { static void F(B b) { b.x = 1 ; // 錯誤 } }
類 B 繼承類 A 的私有成員 x。因為該成員是私有的,所以只能在 A 的"類體"中對它進行訪問。因此,對 b.x 的訪問在 A.F 方法中取得了成功,在 B.F 方法中卻失敗了。
2、繼承中關于屬性的一些問題
和類的成員方法一樣,我們也可以定義屬性的重載、虛屬性、抽象屬性以及密封屬性的概念。與類和方法一樣,屬性的修飾也應符合下列規則:
屬性的重載
1. 在派生類中使用修飾符的屬性,表示對基類中的同名屬性進行重載。
2. 在重載的聲明中,屬性的名稱、類型、訪問修飾符都應該與基類中被繼承的屬性一致。
3. 如果基類的屬性只有一個屬性訪問器,重載后的屬性也應只有一個。但如果基類的屬性同時包含get 和set 屬性訪問器,重載后的屬性可以只有一個,也可以同時有兩個屬性訪問器。
注意:與方法重載不同的是,屬性的重載聲明實際上并沒有聲明新的屬性,而只是為已有的虛屬性提供訪問器的具體實現。
虛屬性
1. 使用virtual 修飾符聲明的屬性為虛屬性。
2. 虛屬性的訪問器包括get 訪問器和set 訪問器,同樣也是虛的。
抽象屬性
1. 使用abstract 修飾符聲明的屬性為抽象屬性。
2. 抽象屬性的訪問器也是虛的,而且沒有提供訪問器的具體實現。這就要求在非虛的派生類中,由派生類自己通過重載屬性來提供對訪問器的具體實現。
3. abstract 和override 修飾符的同時使用,不但表示屬性是抽象的,。而且它重載了基類中的虛屬性這時屬性的訪問器也是抽象的。
4. 抽象屬性只允許在抽象類中聲明。
5. 除了同時使用abstract 和override 修飾符這種情況之外,static, virtual, override和abstract 修飾符中任意兩個不能再同時出現。
密封屬性
1. 使用sealed 修飾符聲明的屬性為密封屬性。類的密封屬性不允許在派生類中被繼承。密封屬性的訪問器同樣也是密封的。
2. 屬性聲明時如果有sealed 修飾符,同時也必須要有override 修飾符。
從上面可以看出,屬性的這些規則與方法十分類似。對于屬性的訪問器,我們可以把get 訪問器看成是一個與屬性修飾符相同、沒有參數、返回值為屬性的值類型的方法,把set 訪問器看成是一個與屬性修飾符相同、僅含有一個value 參數、返回類型為void 的方法?聪旅娴某绦颍
using System ; public enum sex { woman, man, } ; abstract public class People { private string s_name; public virtual string Name { get { return s_name ; } } private sex m_sex ; public virtual sex Sex { get { return m_sex ; } protected string s_card; public abstract string Card { get; set; } }
上面的例子中聲明了"人"這個類,人的姓名Name 和性別Sex 是兩個只讀的虛屬性:身份證號Card 是一個抽象屬性,允許讀寫,因為類People 中包含了抽象屬性Card,所以People 必須聲明是抽象的。下面我們為住宿的客人編寫一個類類從People 中繼承。再看下面的程序:
class Customer: People { string s_no ; int i_day ; public string No { get { return s_no ; } set { if (s_no != value) s_no = value; } } public int Day { get { return i_day ; } set { if (i_day != value) i_day = value; } } public override string Name { get { return base.Name; } } public override sex Sex { get { return base.Sex } } public override string Card { get { return s_ card ; } set { s_ card = value ; } } }
在類Customer 中,屬性Name、 Sex 和Card 的聲明都加上了override 修飾符,屬性的聲明都與基類People 中保持一致。Name 和Sex 的get 訪問器,Card 的get 和set訪問器都使用了base 關鍵字來訪問基類People 中的訪問器屬性。Card 的聲明重載了基類People 中的抽象訪問器。這樣,在Customer 類中沒有抽象成員的存在,Customer可以是非虛的
3、繼承中對使用可訪問性級別的限制
聲明類型時,最重要的是查看該類型是否必須"至少"與其他成員或類型"具有同樣的可訪問性"。例如,直接基類必須至少與派生類具有同樣的可訪問性。以下聲明將導致編譯器錯誤,因為基類 BaseClass 的可訪問性小于 MyClass:
class BaseClass {...} public class MyClass: BaseClass {...} // Error
下表匯總了對使用聲明的可訪問性級別的限制。
上下文 備注 類 類類型的直接基類必須至少與類類型本身具有同樣的可訪問性。 接口 接口類型的顯式基接口必須至少與接口類型本身具有同樣的可訪問性。 委托 委托類型的返回類型和參數類型必須至少與委托類型本身具有同樣的可訪問性。 常數 常數的類型必須至少與常數本身具有同樣的可訪問性。 字段 字段的類型必須與至少字段本身具有同樣的可訪問性。 方法 方法的返回類型和參數類型必須至少與方法本身具有同樣的可訪問性。 屬性 屬性的類型必須至少與屬性本身具有同樣的可訪問性。 事件 事件的類型必須至少與事件本身具有同樣的可訪問性。 索引器 索引器的類型和參數類型必須至少與索引器本身具有同樣的可訪問性。 運算符 運算符的返回類型和參數類型必須至少與運算符本身具有同樣的可訪問性。 構造函數 構造函數的參數類型必須至少與構造函數本身具有同樣的可訪問性。
示例:以下示例包含不同類型的錯誤聲明。每個聲明后的注釋指示了預期的編譯器錯誤。
using System ; delegate int MyDelegate( ) ; class B { // 定義一個私有的函數: static int MyPrivateMethod() { return 0 ; } } public class A { // 字段定義: public B myField = new B();// 錯誤: 類型B與A字段A.myField級別不同 // 構造函數: public readonly B myConst = new B(); //錯誤: 類型B是僅讀的 //方法: public B MyMethod() { return new B(); } //屬性: public B MyProp { set { } } public static B operator + (A m1, B m2) { return new B(); } static void Main() { Console.Write("Compiled successfully"); } }
|