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