類別的繼承
1. 子類別與父類別:
子類別(又稱「衍生類別」)和父類別(又稱「基礎類別」)這兩個名詞,隨著「繼承」這個動作的發生,而一起被定義。我們稱繼承者是子類別,被繼承者是父類別。「子類別繼承父類別」這句話,其意義是「父類別將自己的public、protected的成員與成員函式傳遞給子類別,使子類別在宣告時不必宣告這些成員、成員函式,就能擁有他們」。
子類別的宣告式:
class 子類別名稱 : 父類別名稱
{
類別成員宣告式
類別成員函式宣告式
類別建構式
};
※ 註:在子類別宣告式之內,可用this關鍵字來代表類別本身,而用base關鍵字來代表其父類別(可用base.成員、base.成員函式名稱(參數一,參數二…)來呼叫父類別的成員與成員函式)。
再次強調,父類別中能夠被繼承的只有「public、protected的成員與成員函式」。而父類別的建構式,就算其為public也不能被子類別繼承。子類別之建構式的寫法與一般類別不同(與其父類別的建構式有關),語法為:
存取修飾詞 子類別名稱(參數資料型態一 參數一, 參數資料型態二, 參數二…) : base(父類別建構式參數一, 父類別建構式參數二…)
{
//函式內容(可以不需對賦類別建構式參數進行設定)
}
此語法之形式不易理解,可參考範例:
class person
{
public string name;
public int age;
public person(string n_, int a_)
{ name = n_; age = a_; }
public string self_introduction()
{ return "hi, I'm " + name + "," + age + "years old."; }
};
class boy : person //boy是一個子類別,繼承了父類別person
{
public int money;
public boy(string n_, int a_, int money_) : base(n_, a_)
{ money = money_; } //子類別建構式在此
};
boy b1 = new boy("Jack", 12, 200); //子類別物件之宣告,仍按照子類別建構式的寫法
2. 在子類別重新定義父類別成員函式:
當子類別從父類別繼承了某個成員函式,但卻想改寫這個成員函式時(這個「改寫」,並不會影響父類別物件對該成員函式的使用,而是重新在子類別中定義該成員函式,以供子類別自己所用),有以下兩種方法:
(1) 子類別覆寫父類別的虛擬成員函式:
要成功使用這個方法的前提是:父類別中那個要被重新定義的成員函式,是個「虛擬函式」。虛擬函式的寫法需利用到virtual關鍵字,如下:
存取修飾詞 virtual 回傳資料型態 虛擬成員函式名稱(參數資料型態一 參數一, 參數資料型態二, 參數二…)
{
//函式內容
}
而在子類別中,覆寫該虛擬函式需利用override關鍵字。語法如下:
存取修飾詞 override 回傳資料型態 虛擬成員函式名稱(參數資料型態一 參數一, 參數資料型態二, 參數二…)
{
//函式內容
}
※ 範例如下:
class A
{ public virtual string intro(){ return "this is A";}};
class B : A
{ public override string intro(){ return "this is B"; }};
B b1 = new B();
textBox1.Text = b1.intro(); //顯示this is B
(2) 子類別成員函式直接取代父類別成員函式:
這種方法比較方便,直接在子類別中利用new關鍵字宣告欲取代的成員函式。語法為:
存取修飾詞 new 回傳資料型態 虛擬成員函式名稱(參數資料型態一 參數一, 參數資料型態二, 參數二…)
{
//函式內容
}
※ 範例如下:
class A
{ public string intro(){ return "this is A";}};
class B : A
{ public new string intro(){ return "this is B"; }};
B b1 = new B();
textBox1.Text = b1.intro(); //顯示this is B
3. 父類別物件與子類別物件的轉換:
(1) 父類別物件,不能顯性轉換為子類別物件。
(2) 子類別物件,可以顯性轉換為父類別物件。只不過轉換之後,在該子類別內另行定義的成員和成員函式,將會消失。只有繼承父類別的成員和成員函式會保留下來。顯性轉換的方法為:
(父類別名稱)子類別物件名稱
如,今有一個person類別和一個man類別(且man 類別繼承person類別,故person是父類別相對於man是子類別),一個man類別物件名為wang,則:
person jili_wang = (person)wang;
即可將wang轉成person類別後,儲存在jili_wang這個perosn類別物件裡。
4. 抽象類別與抽象成員函式:
所謂「抽象成員函式」,指的是在該成員函式被宣告時,只有宣告其名稱、回傳資料形態、參數列,卻沒有宣告函式內容(函式內容不在類別本身中宣告,而是在該類別之衍生類別中再去覆寫)。而若某個類別擁有抽象成員函式,就稱其為「抽象類別」(抽象成員函式也只能在抽象類別中宣告)。抽象類別並不能被用來建立物件,而是專門被用來繼承的。這種用法,在較大、複雜的類別架構中,能使程式碼更為簡潔易讀。
抽象類別與抽象成員函式均用到關鍵字abstract。其宣告如下:
(1) 抽象類別的宣告:
abstract class 類別名稱
{
類別成員宣告式
類別成員函式宣告式
類別建構式
};
(2) 抽象成員函式的宣告:
abstract 存取修飾詞 回傳資料型態 成員函式名稱(參數資料型態一 參數一, 參數資料型態二, 參數二…)
※ 註:抽象類別中可以沒有抽象成員函式,但有抽象成員函式的類別一定要宣告成抽象類別,否則程式執行時會出錯。
(3) 抽象成員函式的實作:
抽象成員函式的函式內容不在抽象類別本身中宣告,而是在該抽象類別之衍生類別中去覆寫。「為抽象成員函式寫入函式內容」這個動作,稱為對抽象成員函式的「實作(implement)」。
如以下範例:
abstract class person
{
public string name;
public int age;
public person(string n_, int a_)
{ name = n_; age = a_; }
abstract public string talk(); //抽象成員函式talk()在此
};
class teacher : person
{
public teacher(string n_, int a_)
: base(n_, a_){ }
public override string talk() //實作抽象成員函式talk()
{ return "Hi, My name is " + name + ", nice to meet you!"; }
};
class waiter : person
{
public waiter(string n_, int a_)
: base(n_, a_){ }
public override string talk() //實作抽象成員函式talk()
{ return "Welcome to our bar. Need something?"; }
};
由上範例可知,每個衍生類別對於抽象成員函式都有不同的實作方法,就如同生活中對於每種不同的人(person)進行交談(talk)時,他們的回話都不盡相同。這就是抽象成員函式在應用上的意義。
留言列表