標籤:
(1) 訪問基類成員
通過base 關鍵字訪問基類的成員:
調用基類上已被其他方法重寫的方法。
指定建立衍生類別執行個體時應調用的基類建構函式。
基類訪問只能在建構函式、執行個體方法或執行個體屬性訪問器中進行。
從靜態方法中使用 base 關鍵字是錯誤的。
樣本:下面程式中基類 Person 和衍生類別 Employee 都有一個名為 Getinfo 的方法。通過使用 base 關鍵字,可以從衍生類別中調用基類上的 Getinfo 方法。
using System ;
public class Person
{
protected string ssn = "111-222-333-444" ;
protected string name = "張三" ;
public virtual void GetInfo() {
Console.WriteLine("姓名: {0}", name) ;
Console.WriteLine("編號: {0}", ssn) ;
}
}
class Employee: Person
{
public string id = "ABC567EFG23267" ;
public override void GetInfo() {
// 調用基類的GetInfo方法:
base.GetInfo();
Console.WriteLine("成員ID: {0}", id) ;
}
}
class TestClass {
public static void Main() {
Employee E = new Employee() ;
E.GetInfo() ;
}
}
程式運行輸出:
姓名: 張三
編號: 111-222-333-444
成員ID: ABC567EFG23267
樣本:衍生類別同基類進行通訊。
using System ;
public class Parent
{
string parentString;
public Parent( )
{ Console.WriteLine("Parent Constructor.") ; }
public Parent(string myString) {
parentString = myString;
Console.WriteLine(parentString) ;
}
public void print( )
{ Console.WriteLine("I‘m a Parent Class.") ; }
}
public class Child : Parent
{
public Child( ) : base("From Derived")
{ Console.WriteLine("Child Constructor.") ; }
public void print( ) {
base.print( ) ;
Console.WriteLine("I‘m a Child Class.") ;
}
public static void Main( ) {
Child child = new Child( ) ;
child.print( ) ;
((Parent)child).print( ) ;
}
}
程式運行輸出:
From Derived
Child Constructor.
I‘m a Parent Class.
I‘m a Child Class.
I‘m a Parent Class.
說明:
1.衍生類別在初始化的過程中可以同基類進行通訊。
上面代碼示範了在子類的建構函式定義中是如何?同基類通訊的。分號":"和關鍵字base用來調用帶有相應參數的基類的建構函式。輸出結果中,第一行表明:基類的建構函式最先被調用,其實在參數是字串"From Derived"。
2.有時,對於基類已有定義的方法,打算重新定義自己的實現。
Child類可以自己重新定義print( )方法的實現。Child的print( )方法覆蓋了Parent中的 print 方法。結果是:除非經過特別指明,Parent類中的print方法不會被調用。
3.在Child類的 print( ) 方法中,我們特別指明:調用的是Parent類中的 print( ) 方法。
方法名前面為"base",一旦使用"base"關鍵字之後,你就可以訪問基類的具有公有或者保護許可權的成員。 Child類中的print( )方法的執行結果出現上面的第三行和第四行。
4.訪問基類成員的另外一種方法是:通過顯式類型轉換。
在Child類的Main( )方法中的最後一條語句就是這麼做的。記住:衍生類別是其基類的特例。這個事實告訴我們:可以在衍生類別中進行資料類型的轉換,使其成為基類的一個執行個體。上面代碼的最後一行實際上執行了Parent類中的 print( )方法。
(2) 隱藏基類成員
想想看,如果所有的類都可以被繼承,繼承的濫用會帶來什麼後果?類的階層體系將變得十分龐,大類之間的關係雜亂無章,對類的理解和使用都會變得十分困難。有時候,我們並不希望自己編寫的類被繼承。另一些時候,有的類已經沒有再被繼承的必要。C#提出了一個密封類(sealed class)的概念,協助開發人員來解決這一問題。
密封類在聲明中使用sealed 修飾符,這樣就可以防止該類被其它類繼承。如果試圖將一個密封類作為其它類的基類,C#將提示出錯。理所當然,密封類不能同時又是抽象類別,因為抽象總是希望被繼承的。
在哪些場合下使用密封類呢?密封類可以阻止其它程式員在無意中繼承該類。而且密封類可以起到運行時最佳化的效果。實際上,密封類中不可能有衍生類別。如果密封類執行個體中存在虛成員函數,該成員函數可以轉化為非虛的,函數修飾符virtual 不再生效。
讓我們看下面的例子:
bstract class A
{
public abstract void F( ) ;
}
sealed class B: A
{
public override void F( )
{ // F 的具體實現代碼 }
}
如果我們嘗試寫下面的代碼
class C: B{ }
C#會指出這個錯誤,告訴你B 是一個密封類,不能試圖從B 中派生任何類。
(3) 密封方法
我們已經知道,使用密封類可以防止對類的繼承。C#還提出了密封方法(sealedmethod) 的概念,以防止在方法所在類的衍生類別中對該方法的重載。對方法可以使用sealed 修飾符,這時我們稱該方法是一個密封方法。
不是類的每個成員方法都可以作為密封方法密封方法,必須對基類的虛方法進行重載,提供具體的實現方法。所以,在方法的聲明中,sealed 修飾符總是和override 修飾符同時使用。請看下面的例子代碼:
using System ;
class A
{
public virtual void F( )
{ Console.WriteLine("A.F") ; }
public virtual void G( )
{ Console.WriteLine("A.G") ; }
}
class B: A
{
sealed override public void F( )
{ Console.WriteLine("B.F") ; }
override public void G( )
{ Console.WriteLine("B.G") ; }
}
class C: B
{
override public void G( )
{ Console.WriteLine("C.G") ; }
}
類B 對基類A 中的兩個虛方法均進行了重載,其中F 方法使用了sealed 修飾符,成為一個密封方法。G 方法不是密封方法,所以在B 的衍生類別C 中,可以重載方法G,但不能重載方法F。
(4) 使用 new 修飾符隱藏基類成員
使用 new 修飾符可以顯式隱藏從基類繼承的成員。若要隱藏繼承的成員,請使用相同名稱在衍生類別中聲明該成員,並用 new 修飾符修飾它。
請看下面的類:
public class MyBase
{
public int x ;
public void MyVoke() ;
}
在衍生類別中用 MyVoke名稱聲明成員會隱藏基類中的 MyVoke方法,即:
public class MyDerived : MyBase
{ new public void MyVoke (); }
但是,因為欄位 x 不是通過類似名隱藏的,所以不會影響該欄位。
通過繼承隱藏名稱採用下列形式之一:
a、引入類或結構中的常數、指定、屬性或類型隱藏具有相同名稱的所有基類成員。
b、引入類或結構中的方法隱藏基類中具有相同名稱的屬性、欄位和類型。同時也隱藏具有相同簽名的所有基類方法。
c、引入類或結構中的索引器將隱藏具有相同名稱的所有基類索引器。
注意:在同一成員上同時使用 new 和 override 是錯誤的。同時使用 new 和 virtual 可保證一個新的專用化點。在不隱藏繼承成員的聲明中使用 new 修飾符將發出警告。
樣本1:在該例中,基類 MyBaseC 和衍生類別 MyDerivedC 使用相同的欄位名 x,從而隱藏了繼承欄位的值。該例說明了 new 修飾符的使用。同時也說明了如何使用完全限定名訪問基類的隱藏成員。
using System ;
public class MyBase
{
public static int x = 55 ;
public static int y = 22 ;
}
public class MyDerived : MyBase
{
new public static int x = 100; // 利用new 隱藏基類的x
public static void Main()
{
// 列印x:
Console.WriteLine(x);
//訪問隱藏基類的 x:
Console.WriteLine(MyBase.x);
//列印不隱藏的y:
Console.WriteLine(y);
}
}
輸出: 100 55 22
如果移除 new 修飾符,程式將繼續編譯和運行,但您會收到以下警告:
The keyword new is required on ‘MyDerivedC.x‘ because it hides inherited member ‘MyBaseC.x‘.
如果巢狀型別正在隱藏另一種類型,如下例所示,也可以使用 new 修飾符修改此巢狀型別。
C#繼承機制 訪問與隱藏基類成員