C#中的繼承與多型還有介面
簡單繼承
最簡單的三個類
public class Animal {
public Animal()
{
Debug.Log("Construct Animal!");
}
}
public class Mammal : Animal {
public Mammal()
{
Debug.Log("Construct Mamal!");
}
}
public class Sheep : Mammal { public Sheep() { Debug.Log("Construct Sheep!"); } }
在main裡面
Sheep sheep = new Sheep();
子類的建構函式會依次執行基類的建構函式,沒有異議。
需要注意的是,沒有特別宣告,子類都會自動去找父類中沒有引數的建構函式,如果基類中沒有,則需要在子類的建構函式中呼叫,比如:
public class Animal{
int age;
public Animal(int _age)
{
age = _age;
Debug.Log("Construct Animal!");
}
}
則子類的建構函式就要這樣寫
public Mammal():base(0) { Debug.Log("Construct Mamal!"); }
在基類Animal中新增函式
public void Eat()
{
Debug.Log("Animal Eat!");
}
下面談一下方法的覆蓋
在子類Sheep中覆蓋定義Eat方法
public new void Eat()
{
Debug.Log("Sheep Eat!");
}
這裡的new關鍵字表示隱藏基類中的方法,官方解釋如下:
new 關鍵字可以顯式隱藏從基類繼承的成員。隱藏繼承的成員時,該成員的派生版本將替換基類版本。雖然可以不使用 new 修飾符來隱藏成員,但將收到編譯器警告。如果使用 new 來顯式隱藏成員,將禁止此警告。
測試程式碼:
Sheep sheep = new Sheep();
Animal animal = new Sheep();
sheep.Eat();
animal.Eat();
結果是這樣的
沒有發生多型行為,宣告的基類物件,執行的就是基類方法,宣告的子類物件,執行的就是子類方法。
在子類的函式中,都有一個base變數,可以認為是一個對基類的引用,通過base就可以呼叫基類的方法。
多型
多型就是多型就是父類引用指向子類物件,呼叫方法時會呼叫子類的實現,而不是父類的實現,這叫多型。
基類Animal中定義函式
public virtual void Birth()
{
Debug.Log("Animal Birth!");
}
Sheep中overrride一下
public override void Birth()
{
Debug.Log("Sheep Birth!");
}
測試程式碼
Sheep sheep = new Sheep();
Animal animal = new Sheep();
animal.Birth();
執行結果
有下面兩個需要注意的點
1.子類呼叫父類的方法
當然是直接用base了。
2.繼承鏈中的虛方法
無論在虛擬成員和最初宣告虛擬成員的類之間已聲明瞭多少個類,虛擬成員永遠都是虛擬的。如果類 A 聲明瞭一個虛擬成員,類 B 從 A 派生,類 C 從類 B 派生,則類 C 繼承該虛擬成員,並且可以選擇重寫它,而不管類 B 是否為該成員聲明瞭重寫。
Sealed關鍵字的用法
Sealed關鍵字用來阻止派生類重寫虛擬成員。還是舉例說明。
基類Animal中定義方法
public virtual void Move()
{
Debug.Log("Animal Move!");
}
Mammal中sealed override這個函式
public sealed override void Move()
{
Debug.Log("Mammal Move!");
}
這時候在Sheep中已經無法overide這個函數了,因為在Sheep看來,基類的Move是被當作一個普通函式來處理的,如果要定義自己的Move函式,就要加new,像這樣
public new void Move()
{
Debug.Log("Sheep Move!");
}
寫點程式碼來測試多型性
Animal animal = new Animal(1);
Animal animal1 = new Mammal(1);
Animal animal2 = new Sheep();
Sheep sheep = new Sheep();
animal.Move();
animal1.Move();
animal2.Move();
sheep.Move();
執行結果
第一個無話可說,直接執行了Animal的move函式
第二個,正常的多型
第三個有點意思,多型到Mammal就打住了
第四個就是普通的執行Sheep類的成員函式。
abstract關鍵字的使用
官方解釋:abstract 修飾符指示所修飾的內容缺少實現或未完全實現。abstract 修飾符可用於類、方法、屬性、索引器和事件。在類宣告中使用 abstract 修飾符以指示某個類只能是其他類的基類。標記為抽象或包含在抽象類中的成員必須通過從抽象類派生的類來實現。
接地氣的解釋:abstract類用於搭建子類的框架,子類必須實現其中的abstract方法,使用的也是override關鍵字。
abstract方法和vitual方法的區別
abstract方法沒有函式體,子類一定要有對應方法的實現。
vitual方法子類可以選擇實現也可以選擇不實現。
兩個都可以用於實現多型。
抽象類不能例項化。抽象類的用途是提供一個可供多個派生類共享的通用基類定義。例如,類庫可以定義一個抽象類,將其用作多個類庫函式的引數,並要求使用該庫的程式設計師通過建立派生類來提供自己的類實現。
介面
介面包含類或結構可以實現的一組相關功能的定義。
例如,使用介面可以在類中包括來自多個源的行為。 由於C#語言不支援多重繼承,所以該功能很重要。 此外,如果要模擬結構的繼承,也必須使用介面,因為它們無法實際從另一個結構或類繼承。
定義一個簡單的介面,只有介面函式的定義,沒有實現。
public interface ISay {
void SayHello();
void SayFuck();
}
Sheep繼承ISay介面public class Sheep : Mammal, ISay
則Sheep類中必須要有ISay中定義的介面的定義
public void SayHello()
{
Debug.Log("ISay Hello");
}
public void SayFuck()
{
Debug.Log("ISay SayFuck");
}
測試程式碼
Sheep sheep = new Sheep();
sheep.SayHello();
sheep.SayFuck();
執行結果
介面有下面幾個屬性
介面類似於抽象基類。實現介面的任何類或結構都必須實現其所有成員。
介面無法直接進行例項化。其成員由實現介面的任何類或結構來實現。
介面可以包含事件、索引器、方法和屬性。
介面不包含方法的實現。
一個類或結構可以實現多個介面。一個類可以繼承一個基類,還可實現一個或多個介面。
參考
MSDN