利用簡單的例子講解繼承概念
繼承
繼承是物件導向的重要概念,當在無法更動情況下,想要擴充使用者功能時便可使用到繼承(Inheritance)
例如 : 鳥會飛、呼吸,飛機也會飛但不會呼吸,此時我們可將飛設為共同方法,使得鳥的類別跟飛機類別繼承飛這個方法,這樣就不會產生飛機這個類別有飛跟呼吸兩種方法,因為飛機不會呼吸而覺得很奇怪
namespace ConsoleApplication1
{
public class Fly
{
public int speed;
public void s()
{
Console.WriteLine("時速" + speed);
}
}
class AirPlane : Fly
{
public string name;
public string type;
public void Info()
{
Console.WriteLine("飛機型號" + type + "飛機名稱" + name);
}
static void Main(string[] args)
{
AirPlane c = new AirPlane();
c.type = "Jstar";
c.name = "kiki";
c.speed = 300;
c.Info();
c.s();
}
}
}
這時我們重建方案,利用啟動但不偵錯的輸出結果可以發現,AirPlane繼承了飛這個方法,因此他可以使用飛類別的方法(s)
最終輸出結果
接下來是繼承且繼承的類別包含建構子,建構子(Constructor),就是用來進行物件初始化的方法。
一般來說,例如飛機類別 繼承 Fly 之後就可以使用Fly所開放出來的東西
那麼如果Airplan 繼承 Fly後,想要對Fly進行初始化的動作,那就需要使用繼承建構子了
在建立物件時我們通常都要有初始化的動作。
當Fly類別有建構子時,程式會自行在衍生類別建構子中加上關鍵字base
即使將這段:base 去除仍可以對Fly類別初始化。
Airplane繼承Fly後便會先初始化Fly的建構子,而印出fly類別初始化
(以下程式碼均有簡化,以要敘述的地方為重)
namespace ConsoleApplication1
{
public class Fly
{
public int speed;
public string initial;
public Fly()
{
initial = "fly類別初始化";
Console.WriteLine(initial);
}
}
class AirPlane : Fly
{
public string name;
public string type;
public AirPlane()
:base()
{
}
public void Info()
{
Console.WriteLine("飛機型號" + type + "飛機名稱" + name);
}
static void Main(string[] args)
{
AirPlane c = new AirPlane();
c.type = "Jstar";
c.name = "kiki";
c.speed = 300;
c.Info();
c.s();
}
}
}
但是,若Fly類別為多載建構子則就必須在衍生類別強調是初始化哪個建構子
預設的Fly建構子則會被覆蓋掉
namespace ConsoleApplication1
{
public class Fly
{
public int speed;
public string initial;
public Fly()
{
initial = "fly類別初始化";
Console.WriteLine(initial);
}
public Fly(string name)
{
initial = initial + name;
Console.WriteLine(initial);
}
}
class AirPlane : Fly
{
public string name;
public string type;
public AirPlane()
:base("fly多載")
{
}
public void Info()
{
Console.WriteLine("飛機型號" + type + "飛機名稱" + name);
}
static void Main(string[] args)
{
AirPlane c = new AirPlane();
c.type = "Jstar";
c.name = "kiki";
c.speed = 300;
c.Info();
}
}
}
宣告覆載方法
如果基礎類別宣告了一個虛擬方法,則可以透過override去宣告該方法的另一種實作方法,與java的寫法不太一樣。
例如:
當我們在fly類別增加了一個叫做flyToString的方法,我們希望可以再衍生類別中呼叫基礎類別(fly)的相同方法,則可使用base
namespace ConsoleApplication1
{
public class Fly
{
public int speed;
public string initial;
public Fly()
{
initial = "fly類別初始化";
Console.WriteLine(initial);
}
public Fly(string name)
{
initial = initial + name;
Console.WriteLine(initial);
}
public virtual void flyToString()
{
Console.WriteLine("這是fly原本的string方法");
}
}
class AirPlane : Fly
{
public string name;
public string type;
public AirPlane()
:base("fly多載")
{
}
public override void flyToString()
{
base.flyToString();
//Console.WriteLine("這是airPlaneToString方法");
}
public void Info()
{
Console.WriteLine("飛機型號" + type + "飛機名稱" + name);
}
static void Main(string[] args)
{
AirPlane c = new AirPlane();
c.type = "Jstar";
c.name = "kiki";
c.speed = 300;
c.flyToString();
c.Info();
c.s();
}
}
}
若想要覆蓋本來的方法則必須要在基礎類別要覆蓋的方法前加上Virtual 關鍵字,且衍生類別的方法要在前方加上override,不然在執行程式時,會出現定義不清的警訊
例如:(以下簡化其他程式碼,與上方相同)
class AirPlane : Fly
{
public string name;
public string type;
public AirPlane()
:base("fly多載")
{
}
public override void flyToString()
{
Console.WriteLine("這是airPlaneToString方法");
}
static void Main(string[] args)
{
AirPlane c = new AirPlane();
c.flyToString();
}
}
從輸出結果便可以看到console的結果為我們寫覆蓋方法的字串
若將
public override void flyToString()
{
base.flyToString();
Console.WriteLine("這是airPlaneToString方法");
}
兩者都寫在ovrride的方法中則是先呼叫基礎類別方法再將其覆蓋成後來的方法