補習:C# 面向物件三大特性:封裝、繼承、多型
C# 面向物件三大基本特性
封裝、繼承、多型
1、封裝
隱藏物件的屬性和實現細節,僅對外公開介面,控制在程式中屬性的讀取和修改的訪問級別。
C# 封裝根據具體的需要,設定使用者的訪問許可權,並通過 訪問修飾符 來實現。
一個 訪問修飾符 定義了一個類成員的範圍和可見性。C# 支援的訪問修飾符如下所示:
● public:所有物件都可以訪問;
● private:物件本身在物件內部可以訪問;
● protected:只有該類物件及其子類物件可以訪問;但不可以繼承給子類
● internal:同一個程式集的物件可以訪問;
● protected internal:訪問限於當前程式集或派生自包含類的型別。
讀寫性
只讀 readonly : {get;}
只寫 writeonly : {set;}
讀寫 read-write : {get;set;}
2、繼承
繼承有一個很重要的原則,叫里氏替換原則:子類是父類;
如:
麻雀:鳥(麻雀繼承鳥類),可以說,麻雀是鳥,但不能說鳥是麻雀。
在程式碼裡也一樣。
//前提:Eagle:Bird
var lstBird = new List<Bird>();
Eagle b1 = new Eagle();
lstBird.Add(b1);//是沒毛病的
因為Eagle是Bird,所以List< Bird> 可以新增Eagle。Eagle擁有所有Bird需要的成員,包括private成員。
實際上,子類能繼承父類除了建構函式以外的所有成員,public\protected\private等,與繼承沒有關係,僅是訪問的可見性。子類能繼承父類成員訪問性的所有特性。但對於private,又有比較特殊的地方:子類無法訪問到父類的private成員,也就是說在子類新建一個同名的成員,編輯器是不會提示重名的。但是實際上父類的private成員是被繼承了的,只不過子類無法看到而已。如父類有一個private成員Color,如果父類的函式有一個WriteLine這個成員的函式,如果子類不重寫此函式,輸出是父類的Color;如果子類重寫了,就算函式內容完全一致,輸出的也是子類的Color;
父類的屬性、方法會繼承給子類,子類中可以訪問直接訪問public\internal的成員,但是無法直接訪問private的成員。對於protected修飾的成員,只有在自己的作用範圍內訪問到protected的成員
同理也繼承到了子類處。
如
class Bird
{
public Bird(string sName,int sSize)
{
Name = sName;
Size = sSize;
}
protected string Name;
public int Size;
public virtual void Cry()
{
Console.WriteLine("i am Bird");
}
public void GetName()
{
Console.WriteLine(Name);
}
}
class Eagle : Bird
{
public Eagle(string Name, int Size) : base(sName: Name, sSize: Size){}
public override void Cry()
{
Console.WriteLine($"i am {Name} ! come ,chickens");
}
}
在Eagle類的內部,重寫了Cry方法,可以直接訪問到繼承的protected成員Name。
而在
class Program
{
static void Main(string[] args)
{
var b1 = new Eagle("Huge",75);
var b1Name = b1.Name;
}
}
在上述程式碼中則會報錯:
僅能在內部訪問,例項化後的成員不可訪問。
3、多型
簡單來說,多型指同一個實體同時具有多種形式。
重寫 是多型的一個重要形式。
父類有一個virtual的方法,則子類可以繼承並重寫這個方法。
我舉個例子。
class Program
{
static void Main(string[] args)
{
var birdList = new List<Bird>();
var b1 = new Eagle("Huge",75);
var b2 = new Sparrow("Tiny", 12);
birdList.Add(b2);
birdList.Add(b1);
foreach (var b in birdList)
{
b.Cry();
}
Console.Read();
}
}
class Bird
{
public Bird(string sName,int sSize)
{
Name = sName;
Size = sSize;
}
protected string Name;
public int Size;
public virtual void Cry()
{
Console.WriteLine("i am Bird");
}
public void GetName()
{
Console.WriteLine(Name);
}
}
class Eagle : Bird
{
public Eagle(string Name, int Size) : base(sName: Name, sSize: Size){}
public override void Cry()
{
Console.WriteLine($"i am {Name} ! come ,chickens");
}
}
class Sparrow : Bird
{
public Sparrow(string Name, int Size) : base(sName: Name, sSize: Size) { }
public override void Cry()
{
Console.WriteLine($"i am {Name} ! ");
}
}
操作結果如下:
即:不同的基類的同名方法實現了不同的操作,這就是重寫,多型的體現。
多型還有其他體現方式,下回再補充。
補充一下:過載
過載與重寫不同,過載是同名方法不同引數而體現出不同的操作,建構函式就是一個例子。一個類可以有多個建構函式,引數型別、引數個數成為區別函式主體的條件。