1. 程式人生 > >《隨筆十五》——C#中的 “ C#中的類定義、介面定義、遮蔽基類成員、 ”

《隨筆十五》——C#中的 “ C#中的類定義、介面定義、遮蔽基類成員、 ”

目錄

C#中的類定義

介面的定義

遮蔽基類成員

基類訪問


C#中的類定義


class MyClass
{
  //Members
}

●   這樣定義一個類後,就可以在專案中能訪問該定義的其他位置對該類進行例項化。 在預設情況下, 類是內部的(internal)—— 即只有當前工程中的程式碼能夠訪問。    可以使用關鍵字 internal 寫在  class 的前面 來顯式指定這一點。

●   還可以使用關鍵字public 指定類是公共的—— 即可以在任何專案工程中的程式碼來訪問。

●   還可以使用關鍵字abstract 指定類是抽象類(該類只能被繼承,不能被例項化,可以有抽象成員),抽象類 也可以是 internal  和 public 的 可訪問性。

●   還可以使用關鍵字 sealed 指定類是 密封類(該類不能被繼承,就是不能做基類)密封類 也可以是 internal 類 和 public 類 的 可訪問性。

class MyClass : base
{
  //Members
}

上述程式碼在類定義中指定繼承,表示該類被描述為直接繼承自該基類。

●  注意:  除了特殊的類 object,  所有的類都是派生類, 即使它們沒有 顯式指定繼承的基類說明。 類object 是唯一的非派生類, 因為它是繼承層次結構的基礎。 所以說,如果沒有使用基類,被定義的類只繼承於基類 object。

注意: 在C# 中一個類只能有一個基類,稱為單繼承。

●  雖然類只能直接繼承一個基類, 但繼承的層次沒有限制。  也就說,作為基類的類可以派生自另外一個類, 而這個類又派生自另外一個類。 一直下去,直至最終到達object。

基類和派生類是相對的術語。 所有的類都是派生類,要麼派生自object, 要麼派生自其它的類。 所以, 通常當我們稱一個類為派生類時, 我們的意思是它直接派生自某類而不是object。

注意: 編譯器不允許派生類的可訪問性高於基類, 也就說, 內部類可以繼承於一個公共基類,但公共類不能繼承於一個內部基類。


介面的定義


●  使用關鍵字 interface 來定義介面,語法為:

interface  myInterface
{
  //interface members
}

●  在預設情況下, 介面是內部的(internal)—— 即只有當前工程中的程式碼能夠訪問。    可以使用關鍵字 internal 寫在  interface 的前面 來顯式指定這一點。

●   還可以使用關鍵字public 指定介面是公共的—— 即可以在任何專案工程中的程式碼來訪問。

●  不可以在介面中使用  abstract 和 sealed  , 因為這兩個關鍵字在介面中是沒有意義的。

●  也可以使用 與類繼承類似的方式來指定介面的繼承。 主要區別是可以使用多個集介面:

interface IMyInterface : IMyBaseInterface, IMyBaseInterface2
{
   // Interface members

}

介面不是類,所以沒有繼承object, 但是object 的成員  可以通過介面型別的變數來訪問。  如上所述, 不能用例項化類的方式來例項化介面。


●   除了可以在類的後面指定基類外, 還可以在冒號的後面指定支援的介面。  如果指定了基類,它必須緊跟冒號之後, 之後才是介面。  如果未指定基類, 介面就緊跟在冒號的後面。 必須使用逗號來分隔基類名 ( 如果有基類的話 ) 和介面名。

class MyClass : MyBase,IMyBaseInterface, IMyBaseInterface2
{
   // Class members

}

上述的類指定了一個基類,兩個介面。 支援該介面的類必須實現所有介面的成員, 但如果不想使用給定的介面成員, 可以提供一種 “ 空” 的實現方式 (沒有函式程式碼), 還可以把介面成員實現為抽象類中的抽象成員。

 


遮蔽基類成員


●  有時候我們要繼承包含某個特殊方法的基類。 該方法雖然適合宣告它的類, 但卻不一定適合派生類。 在這種情況下, 我們希望在派生類中宣告新成員遮蔽基類中的方法

下面看一個示例程式,仔細觀察註釋 和程式碼

namespace HelloWorld_Console
{
    class SomeClass
    {
        // 注意: 基類中的成員 只有保護的和公有的才會被派生類隱藏, 私有的成員不會被隱藏。
        public string Field1 = " 基類中的欄位宣告.";
        public void Method1()
        {
            WriteLine($"基類中的Method1方法");
        }
        public static int Field2;
    }
    class OtherClass : SomeClass
    {
        new public static double Field2;  //還可以遮蔽靜態成員

        // public int Field1 = 0;錯誤,雖然該欄位的返回型別不同,名稱跟基類中的相同,但是還是需要使用 new 前輟。
        new public string Field1 = " 派生類中的欄位宣告.";
        new public int Method1() // 雖然該成員函式的返回型別是int, 名稱跟基類中的一樣,但是還是需要前輟new
        {// 通過在派生類中宣告新得帶有相同簽名的成員函式,那麼該派生類中的該函式會遮蔽掉基類中相同簽名的成員函式。
         /* 注意: 成員函式的簽名由 名稱和引數列表組成, 不包含返回型別。如果派生類中的 Method1 該函式新增一個
         形參, 就不需要前輟new,  因為它們兩個是不一樣的函式簽名 (C++ 中 與這裡不一樣) */
            WriteLine($"派生類中的Method1方法");
            return 0;
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            OtherClass oc = new OtherClass();
            oc.Method1();
            ReadKey();
        }
    }
}

看一個基類引用的程式:

namespace HelloWorld_Console
{
    class SomeClass
    {
        public string Field1 = " 基類中的欄位宣告.";
        public void Method1()
        {
            WriteLine($"基類中的Method1方法");
        }
        public static int Field2;
    }
    class OtherClass : SomeClass
    {
        new public static double Field2;  //還可以遮蔽靜態成員

        // public int Field1 = 0;錯誤,雖然該欄位的返回型別不同,名稱跟基類中的相同,但是還是需要使用 new 前輟。
        new public string Field1 = " 派生類中的欄位宣告.";
        new public int Method1() // 雖然該成員函式的返回型別是int, 名稱跟基類中的一樣,但是還是需要前輟new
        {// 通過在派生類中宣告新得帶有相同簽名的成員函式,那麼該派生類中的該函式會遮蔽掉基類中相同簽名的成員函式。
         /* 注意: 成員函式的簽名由 名稱和引數列表組成, 不包含返回型別。如果派生類中的 Method1 該函式新增一個
         形參, 就不需要前輟new,  因為它們兩個是不一樣的函式簽名 */
            WriteLine($"派生類中的Method1方法");
            return 0;
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            OtherClass oc = new OtherClass();
            oc.Method1(); // 呼叫的是派生類中的該函式
            SomeClass mySomeClass = (SomeClass)oc; //是一個基類引用派生類物件
            mySomeClass.Method1(); // 這裡呼叫的是基類中的該函式
            ReadKey();
        }
    }
}

基類訪問


如果在派生類中想訪問被隱藏的基類中的繼承成員, 可以在派生類中 顯式用  base. 成員名 來訪問基類中被隱藏的成員。

namespace HelloWorld_Console
{
    class SomeClass
    {
        public string Field1 = " 基類中的欄位宣告.";
        public void Method1()
        {
            WriteLine($"基類中的Method1方法");
        }
    }
    class OtherClass : SomeClass
    {
      
        new public string Field1 = " 派生類中的欄位宣告.";
        new public void Method1()
        { 
            WriteLine(Field1);
            WriteLine(base.Field1); //訪問派生類中的欄位
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            OtherClass oc = new OtherClass();
            oc.Method1();
        
            SomeClass mySomeClass = (SomeClass)oc; //是一個基類引用派生類物件
            mySomeClass.Method1(); // 這裡呼叫的是基類中的該函式
            ReadKey();
        }
    }
}

輸出結果為:
 派生類中的欄位宣告.
 基類中的欄位宣告.
基類中的Method1方法