繼承
經常會需要擴展現有的類型來添加方法或數據。比如我們首先有一個Student類來存儲學生的姓名、年齡等信息,現在需要建立一個類BoyStudent來存儲男同學的興趣愛好。因為每個男同學都是學生,因此Students類中的所有內容都應該被包含在BoyStudent類;另一方面,BoyStudent類中還包含Student類中不包含的內容,如興趣的種類。在這種情況下,BoyStudent類就可以在Student類的基礎上建立,即在Student類的基礎上添加新的內容。我們可以稱BoyStudent類繼承自Student類,其中Student類稱為基類,BoyStudent稱為派生類。
來看兩段代碼。
//基類
public class Student
{
public string Name{get;set}
private int Age{get;set}
public virtual string Teacher{get;set}//允許重寫的屬性
}
// 派生類
public class BoyStudent : Student
{
public string Hobby{get;set}
public string TeacherName;
public override string Teacher
{
get
{
return $"Dear {TeacherName}";
}
set
{
TeacherName = value;
}
}
}
// 調用
public class Program
{
public static void Main()
{
BoyStudent boyStudentTom = new BoyStiudent();
boyStudent1.Name = "Tom";
Student studentTom = boyStudentTom;// 類型轉換
}
}
- 繼承的標識符是":","A:B"表示類A繼承自類B。
- C#的類是單繼承的,這意味着":"后面只能寫一個類。
- 如調用中的函數所示,雖然沒有在BoyStudent類中定義Name屬性,但是在它的基類Student中有public的Name屬性,因此可以直接進行訪問,或者說,每個派生類繼承除構造函數和析構器之外的所有基類成員。但是繼承不意味着可以訪問,Student類中的Age屬性,被限定為private,它不可以在派生類中進行訪問。除了public和private這兩個極端的修飾,還有一個折中的修飾符protected,它意味着改成員只有基類及其派生類可以訪問。
- 派生類可以轉換成基類,調用中轉換的代碼是隱式轉換,也可以使用顯式轉換。但是注意,派生類向基類轉換是可以的,但是基類向派生類轉換不可以。因為派生類一定屬於基類,但是基類不一定屬於派生類。
- 如果基類中的某些成員不太滿足派生類的要求,可以在派生類中重寫。但是C#只支持重寫實例方法和屬性,不支持字段和任何靜態成員的重寫。此外,必須在基類中將每個允許重寫的成員都用virtual修飾符修飾,在派生類重寫時,要加上override修飾符。
- 如果不希望被重寫,可以對成員加上sealed修飾符修飾。
- 所有的類直接或間接從object派生。
- 有一種類是抽象類,其抽象成員定義了從抽象實體派生的對象應包含什么,但這種成員不包含實現。抽象類的大多數功能通常都沒有實現。一個類要從抽象類成功地派生,必須為抽象基類中的抽象方法提供具體的實現。抽象類需要在類前加abstract修飾符修飾。
接口
接口有點像協議,在其中定義實現的某些功能的方法名稱和這些方法需要的參數類型。這樣的話,該接口的所有派生類的實例,在調用該方法時就會有統一的格式。
// 定義接口
interface IfileWrite
{
void FileWrite(string address,string fileName);
}
- 接口用interface關鍵字聲明,按照約定,接口的名稱最好加一個I前綴。
- 接口不包含實現和數據,在接口中不能出現字段,但是可以包含屬性,屬性不能引用支持字段,接口中也不能擁有靜態成員。
- C#不允許為接口成員使用訪問修飾符,所有成員自動公共。
- 接口永遠不能實例化,接口不含有構造函數和終結器。
// 接口派生類
class Example:IfileWrite
{
public void FileWrite(string address,string fileName)
{
...//具體實現
}
}
- 聲明類來實現接口類似於從基類派生——要實現的接口和基類名稱以逗號分隔(基類在前,接口順序任意)。類可實現多個接口,但只能從一個基類直接派生。
- 實現接口時,接口的所有成員都必須實現。實現方式有顯式實現和隱式實現兩種,上文的例子是隱式實現。
- 一個接口可以從另一個或多個接口派生,派生的接口將繼承“基接口”的所有成員。