多態 1 認識多態 1.1 基本概念 多態是同一個行為具有多個不同表現形式或形態的能力,意味著有多重形式。在面向對象編程範式中,多態性往往表現為"一個介面,多個功能"。 在 C# 中,每個類型都是多態的,因為包括用戶定義類型在內的所有類型都繼承自 Object。 多態性分為靜態的和動態多態。在靜態多 ...
多態
1 認識多態
1.1 基本概念
多態是同一個行為具有多個不同表現形式或形態的能力,意味著有多重形式。在面向對象編程範式中,多態性往往表現為"一個介面,多個功能"。
在 C# 中,每個類型都是多態的,因為包括用戶定義類型在內的所有類型都繼承自 Object。
多態性分為靜態的和動態多態。在靜態多態性中,函數的響應是在編譯時發生的。在動態多態性中,函數的響應是在運行時發生的。
- 靜態多態:函數重載、運算符重載
- 動態多態:vob(virtual 虛函數,override 重寫,base 父類)、抽象函數、介面
1.2 使用
class GameObject
{
public string name;
public GameObject(string name)
{
this.name = name;
}
//虛函數 可以被子類重寫
public virtual void Atk()
{
Console.WriteLine("游戲對象進行攻擊");
}
}
class Player : GameObject
{
public Player(string name) : base(name)//調用父類的構造函數
{
}
//重寫虛函數
public override void Atk()
{
Console.WriteLine("玩家對象進行攻擊");
}
}
class Monster : GameObject
{
public Monster(string name) : base(name)
{
}
public override void Atk()
{
base.Atk();//base代表父類,可以通過它來保留父類的行為,會調用一次父類的方法
Console.WriteLine("怪物對象進行攻擊");
}
}
class Father
{
public void SpeakName()
{
Console.WriteLine("Father的方法");
}
}
class Son : Father
{
public new void SpeakName()
{
Console.WriteLine("Son的方法");
}
}
//Main
//用父類取裝載子類的對象時,有兩個同名的方法,會優先調用父類的 多態就用來解決這類問題
Father f = new Son();
f.SpeakName();
(f as Son).SpeakName();
GameObject p = new Player("abc");//虛函數和重寫解決了問題
p.Atk();
GameObject m = new Monster("def");
m.Atk();
/*
輸出:
Father的方法
Son的方法
玩家對象進行攻擊
游戲對象進行攻擊
怪物對象進行攻擊
*/
2 abstract 抽象類和抽象方法
2.1 抽象類
用 abstract 關鍵字修飾的類。
特點:
- 不能被實例化
- 可以包含抽象方法
- 繼承抽象類必須重寫其抽象方法
abstract class Thing//抽象一類物品
{
public string name;
//可以在抽象類中寫抽象函數
}
class Water : Thing
{
}
2.2 抽象方法
用 abstract 修飾的方法,又叫 純虛方法
特點:
- 只能在抽象類中聲明
- 沒有方法體
- 不能是私有的
- 繼承後必須實現,用override重寫
abstract class Fruits
{
public string name;
public virtual void Test()
{
//虛方法可以寫邏輯
}
public abstract void Bad();//抽象方法
}
class Apple : Fruits
{
//虛方法在子類中可以選擇是否重寫
//抽象方法一定要重寫
public override void Bad()
{
}
}
3 介面
3.1 基本概念
關鍵字:interface,介面是行為的抽象規範,是抽象行為的“基類”,各種類通過繼承它來實現對應的行為。
介面聲明規範:
- 不包含成員變數
- 只包含方法、屬性、索引器、事件
- 成員不能被實現
- 成員可以不寫訪問修飾符,而且不能是私有的
- 介面不能繼承類,但是介面可以繼承另一個介面
介面使用規範:
- 類可以繼承多個介面
- 類繼承介面後,必須實現介面中所有成員
特點:
- 它和類的聲明類似
- 介面是用來繼承的
- 介面不能被實例化,但可以作為容器來存儲對象
3.2 聲明
/*
interface 介面名
{
}
介面名:I+帕斯卡命名法
*/
interface IFly
{
void Fly();//方法
string Name//屬性
{
get;
set;
}
int this[int index]//索引
{
get;
set;
}
event Action doSomething;//事件
}
3.3 使用
介面用來繼承:
- 類可以繼承1個類,n個介面
- 繼承了介面後,必須實現其中的內容,而且必須為 public 的
- 實現的介面函數,可以加 visual 再在子類中 override
- 介面遵循里氏替換原則
class Animal
{
}
class Tiger : Animal, IFly//繼承類和介面
{
//實現介面內容
public void Fly()
{
}
public string Name
{
get;
set;
}
public int this[int index]
{
get
{
return 0;
}
set
{
}
}
public event Action doSomething;
}
3.4 介面繼承介面
- 介面繼承介面時,不需要實現
- 類繼承介面後,去實現介面的所有內容
interface IWalk
{
void Walk();
}
interface IMove : IFly, IWalk
{
}
class Test : IMove//實現所有內容
{
public int this[int index]
{
get => throw new NotImplementedException(); set => throw new NotImplementedException();
}
public string Name
{
get => throw new NotImplementedException(); set => throw new NotImplementedException();
}
public event Action doSomething;
public void Fly()
{
throw new NotImplementedException();
}
public void Walk()
{
throw new NotImplementedException();
}
}
3.5 顯示實現介面
- 當一個類繼承兩個介面,但是介面中存在著同名方法時使用
- 註意:顯示實現介面時,不能寫訪問修飾符
interface IAtk
{
void Atk();
}
interface ISuperAtk
{
void Atk();
}
class Player : IAtk, ISuperAtk
{
//顯示實現介面:介面名.行為名
void IAtk.Atk()
{
}
void ISuperAtk.Atk()
{
}
}
4 sealed 密封方法
4.1 基本概念
- 密封方法:用 sealed 修飾的重寫函數,讓虛方法或抽象方法不能再被重寫,和 override 一起出現
- 密封類:用 sealed 修飾的類,讓類不能被繼承
4.2 使用
abstract class Animal
{
public string name;
public abstract void Eat();
public virtual void Speak()
{
Console.WriteLine("giao");
}
}
class Person : Animal
{
public override void Eat()
{
}
public override void Speak()
{
}
}
class WhitePerson : Person
{
public sealed override void Eat()//不能重寫了
{
base.Eat();
}
public override void Speak()
{
base.Speak();
}
}