1. 程式人生 > >C#本質論6.0第六章:繼承

C#本質論6.0第六章:繼承

行為 實體 sta 密封類 類型 繼承鏈 tac 預測 兩個類

基類型與派生類型之間的轉型:

顯式轉型與隱式轉型:

從派生類型轉型為基類型稱為隱式轉型,轉型總會成功,不會引發異常。

從基類型轉型為派生類型稱為顯式轉型,在轉型過程中可能會失敗,為了執行顯示轉型,要在原始引用名稱之前,將要轉換成的類型放在前面圓括號中。

自定義轉換:

不相關的類型之間也能進行相互轉換,C#允許類型包含顯式與隱式轉型轉換符,在轉型有可能失敗時,開發者應定義顯式轉型操作符。

class GPSCoordinates
{
    //...
    public static implicit operator UTMCoordinates(
        GPSCoordinates coordinates)
    {
        //implicit 隱式轉換關鍵字
        //explicit 顯式轉換關鍵字
    }
}

單繼承:

一個類不能直接從兩個類派生。

在極少數需要多繼承結構的時候,一般的解決方案是使用聚合

  • 聚合:一個類包含另一個類的實例。
public class PdaItem
{
    //主要基類
}
public class Person
{
    //字段類
}
public class Contact : PdaItem
{   //派生類
    //持有另一個類的實例
    private Person InternalPerson{get; set;}
    public string FirstName
    {
        get{return InternalPerson.FirstName;}
        set{InternalPerson.FirstName = value;}
    }
    //...
}

缺點:

1. 因委托而增加復雜性。
?   2. 在字段類上新增的任何方法都需要人工添加到派生類中,否則Contact無法公開新增的功能。

密封類:

為了正確設計類,讓其他人通過繼承來拓展它的功能,需要對它進行全面測試,驗證派生能成功的進行。為了避免非預期的派生,並避免出現因此而產生的問題,可以把類標記為sealed

public sealed class CommandLineParser
{
    //...不能從該類派生出其他類
}

基類的重寫:

在基類中,必須將允許重寫的每個成員標記為virtual,假如一個public或protected成員沒有包含virtual修飾符,就不允許子類重寫該成員。

public class PdaItem
{
    public virtual string Name{get;set;}
}

public class Contact : PdaItem
{
    public override string Name
    {
        //...
    }
}
  • 對成員進行重載,會造成運行時調用最深的或者說派生的最遠的實現。因此,虛方法不應包含關鍵代碼,如果派生類重寫了它,那麽那些代碼將永遠得不到調用。不要在構造器中調用會影響所構造對象的任何虛方法,假如這個虛方法在當前要實例化的類型的派生類型中進行了重寫,就會調用重寫的實現,但在繼承層次結構中,字段尚未完全初始化,所以調用虛方法將導致無法預測的行為。
  • 如果沒有對虛方法進行重寫,編譯器會報告警告信息,我們可以通過new關鍵字來解決該問題:
    • new修飾符在基類面前隱藏了派生類重新聲明的成員,這時不是調用派生的最遠的成員,相反,是搜索繼承鏈,找到使用new修飾符的那個成員之前的成員,然後調用該成員。如果繼承鏈中僅包含兩個類,就會使用基類的成員,感覺就像是派生類沒有重寫那個成員。
  • 對類使用sealed修飾符可以禁止從該類繼承,虛成員也可以密封。一般很少將整個類標記為密封,除非是遇到迫切需要這種限制的情況。
  • base成員:重寫成員時,調用該成員的基類版本。
  • override修飾的任何成員都自動成為虛成員。

構造器:

在實例化一個派生類的時候,運行時首先調用基類的構造器,以避免繞過對基類的初始化。假如基類沒有可訪問的默認構造器,我們需要在派生類構造器的頭部顯式指定要運行哪一個基類構造器。

public class Contact : PdaItem
{
    public Contact(string name):base(name)
    {
        Name = name;
    }
}

抽象類:

(abstract)抽象類是僅供派生的類,無法實例化抽象類,只能實例化從它派生的類。抽象成員定義了從抽象實體派生的對象應包含什麽,但這種成員不包含實現。一個類要從抽象類成功的派生,必須為抽象基類的抽象方法提供具體的實現。

  • 不可實例化只是抽象類的一個較次要的特征,其主要特征是它包含抽象成員,抽象成員是沒有實現的方法或屬性,其作用是強制所有派生類提供實現。

is&as

  • is操作符可以用來判斷基礎類型,並非僅僅是檢查數據能否成功轉型為目標類型,還會檢查底層對象本身是否是目標類型,如果不是,返回false
  • as嘗試將對象轉換成特定數據類型,當不能轉換的時候,as操作符會返回null。

C#本質論6.0第六章:繼承