C#中類的繼承與派生在性質上類似C++,但在有些方面有一些區別。
C#中所有類都派生自object類
除了特殊的類object,所有的類都是派生類,即使他們沒有基類規格說明,類object是唯一的非派生類,因爲他是繼承層次結構的基礎,與C++不同(C++中允許多繼承),在C#中一個類聲明的基類規格說明中只能有一個單獨的類,也就是隻允許單繼承,雖然類只能直接繼承一個基類,但繼承的層次沒有限制。在寫法上也與C++不同,C#中不存在公有繼承、私有繼承等這些繼承方式,所以在寫的時候冒號後面直接接上基類的名字即可,例如 class A : B
屏蔽基類成員
雖然子類不能刪除它繼承的任何成員,但可以用與父類成員名稱相同的成員來屏蔽(mask)父類成員,這是繼承的主要功能之一。
屏蔽的使用:
(1)屏蔽一個繼承的數據成員,需要聲明一個新的相同類型的成員,並使用相同名稱
(2)屏蔽一個繼承的函數成員,需要聲明一個帶有相同簽名的函數成員,簽名由名稱和參數列表組成,不包括返回類型
(3)要讓編譯器知道你在故意屏蔽繼承的成員,可以使用new修飾符,否則,程序可以成功編譯,但編譯器會警告你隱藏了一個繼承的成員
(4)也可以屏蔽靜態成員
class A
{
public int i;
public void foo(){ }
}
class B :A
{
new public int i;
public void foo() { } //不加new會有一個警告
}
基類訪問
表達式:base.成員
虛方法(virtual)和覆寫方法(override)
類似C++中的多態的產生,C++中使用子類對象給父類指針賦值,當該父類指針調用虛函數時,就會產生多態,同理C#中使用子類對象的棧上引用給父類引用賦值,當父類引用調用虛方法時,就會產生多態。
class A
{
public virtual void foo()
{
Console.WriteLine("父類");
}
}
class B :A
{
public override void foo()
{
Console.WriteLine("子類");
}
}
class Program
{
static void Main(string[] args)
{
B b = new B();
A a = (A)b;
a.foo(); //輸出子類
}
}
virtual和override修飾符的使用
父類中被覆寫的方法用virtual來修飾,子類中覆寫後的方法需要用override來修飾
(1)覆寫和被覆寫的方法必須有相同的可訪問性
(2)不能覆寫static方法或非虛方法
(3)方法、屬性、索引器以及事件,都可以被聲明爲virtual和override
virtual與override的內部調用機制
當使用對象基類部分的引用調用一個覆寫的方法時,方法的調用被沿派生層次上溯執行,取尋找標記爲override的方法,如果在更高的派生級別有該方法的其他聲明,但沒有被標記爲override,那麼它們不會被調用
class A
{
public virtual void foo()
{
Console.WriteLine("A");
}
}
class B :A
{
public override void foo()
{
Console.WriteLine("B");
}
}
class C:B
{
public override void foo()
{
Console.WriteLine("C");
}
}
class Program
{
static void Main(string[] args)
{
C c = new C();
A a = (A)c;
a.foo(); //輸出C
}
}
此時a調用foo函數,會根據繼承關係向上尋找override方法,在C中有此方法則會調用到C中的foo所以打印出C
class C:B
{
public new void foo()
{
Console.WriteLine("C");
}
}
class Program
{
static void Main(string[] args)
{
C c = new C();
A a = (A)c;
a.foo(); //輸出B
}
}
如果將C中的foo函數使用new來修飾,而不是override,則在調用時找不到C中的override修飾的foo函數,則只能調用B中被override修飾的foo函數所以輸出爲B。