- C# 2012程序設計實踐教程 (清華電腦學堂)
- 張冬旭
- 2632字
- 2021-03-26 17:16:29
3.4 三大特性
封裝、繼承和多態是面向對象編程的三大特性。C#是面向對象編程的,因此這也是類的三大特性。本節簡單介紹一下類的封裝性、繼承性和多態性。
3.4.1 封裝
對于一個具有豐富結構化程序設計經驗的開發者來說,面向對象的程序設計可能會給他們帶來非常不自然的感覺。封裝是實現面向對象程序設計的第一步,它將數據或函數等集合在一個一個的單元中。被封裝的對象通常稱為抽象數據類型。
簡單來說,可以把程序按某種規則分成很多“塊”,塊與塊之間可能會有聯系,每個塊都有一個可變的部分和一個穩定的部分。開發者需要把可變的部分和穩定的部分進行分離,將穩定的部分暴露給其他塊,而將可變的部分隱藏起來,以便隨時修改,這項工作就是封裝。例如,在用類實現某個邏輯時,類就是所說的“塊”,實現功能的具體代碼就是可變的部分,而public的方法或者屬性則是最穩定的部分。
封裝的意義在于保護或防止代碼(即數據)被開發者無意破壞。封裝提供一個有效的途徑來保護數據不被意外地破壞。C#中有兩種方法用以封裝數據。第一種方式是使用傳統的存、取方法;第二種方式是使用屬性。無論使用哪種方法,其目標都是在使用數據的同時不能使它受到任何的破壞和改變,好處如下。
(1)使用者只需要了解如何通過類的接口使用類,而不用關心類的內部數據結構和數據組織方法。
(2)“高內聚,低耦合”一直是開發者所追求的,使用好封裝恰恰可以減少耦合。
(3)只要對外接口不改變,可以任意修改內部實現,這樣可以很好地應對變化。
(4)類具有簡潔清晰的對外接口,縮短了使用者的學習過程。
【范例12】
通過傳統的存、取方法演示封裝,首先定義Department類,為了操作這個類中的數據,在該類中定義一個讀取方法和一個寫入方法,代碼如下。
public class Department { private string departname; public string GetDepartname(){ //讀方法 return departname; } public void SetDepartname(string a) { //寫方法 departname = a; } }
通過使用上述方法可以保護私有數據不被外部程序所破壞,在Main()方法中使用SetDepartname()方法寫入數據,使用GetDepartname()方法讀取數據,代碼如下。
static void Main(string[] args) { Department d = new Department(); d.SetDepartname("會計部"); Console.WriteLine("該部門是 :" + d.GetDepartname()); Console.ReadLine(); }
試一試
使用傳統的讀寫方法封裝數據很好,但是用屬性來實現封裝會更加方便。在3.3.3節已經介紹過屬性封裝,這里不再詳細介紹。感興趣的讀者可以更改范例12中的代碼,通過屬性實現封裝。
3.4.2 繼承
繼承是指一個對象直接使用另一對象的屬性和方法,它是面向對象程序設計的主要特征之一,其好處在于代碼重用,節省程序設計的時間。當一個類A能夠獲取另一個類B中所有非私有的數據和操作的定義作為自己的部分或者全部內容時,就稱這兩個類之間具有繼承關系。被繼承的類B稱為父類或者超類,繼承父類或者超類的數據和操作的類A稱為子類或者派生類。
一個父類可以擁有多個子類,一個子類也可以成為其他類的父類,如圖3-2所示反映了交通工具類的繼承關系。在圖3-2中,交通工具是一個父類,船、汽車和飛機都是交通工具的直接子類,而它們又可以作為其他類的父類。以船為例,它不僅是交通工具的子類,也是汽艇和輪船的父類。

圖3-2 交通工具類的繼承關系
C#中繼承的實現語法如下:
[訪問權限] class <派生類名>:<父類名> { //派生類定義 }
【范例13】
首先定義表示交通工具的Vehicle類,該類中包含兩個受保護的字段,無參構造函數、有參構造函數以及公有的Speak()方法,代碼如下。
class Vehicle { protected int wheels; //輪子個數 protected float weight; //重量 public Vehicle() { } //無參構造 public Vehicle(int w, float g) { //有參構造 wheels = w; weight = g; } public void Speak() { Console.WriteLine("交通工具的輪子個數是可以變化的! "); } } ;
接著定義表示汽車的Car類,該類繼承自Vehicle類,實現繼承時需要在Car類后跟“:Vehicle”,代碼如下。
class Car : Vehicle { private int passengers; //私有成員:乘客數 public Car(int w, float g, int p) : base(w, g) { wheels = w; weight = g; passengers = p; } }
上述代碼中,Car類繼承了Vehicle類中的公有方法和受保護的屬性。它還可以包含自身的特性,如可以載客,passengers表示載客人數。
C#中實現繼承時遵循以下幾個規則。
(1)繼承是可傳遞的。如果C從B中派生,B又從A中派生,那么C不僅繼承B中聲明的成員,同樣也繼承A中的成員。Object類作為所有類的父類。
(2)子類應當是對父類的擴展。子類可以添加新的成員,但不能除去已經繼承的成員的定義。
(3)構造函數和析構函數不能被繼承。除此以外的其他成員,不論對它們定義了怎樣的訪問方式,都能被繼承。父類中成員的訪問方式只能決定子類能否訪問它們。
(4)子類如果定義了與繼承而來的成員同名的新成員,就可以覆蓋已繼承的成員。但這并不因為這個子類刪除了這些成員,只是不能再訪問這些成員。
(5)類可以定義虛方法、虛屬性以及虛索引指示器,它的子類能夠重載這些成員,從而實現類可以展示出多態性。
(6)子類只能從一個類中繼承,可以通過接口實現多重繼承。
3.4.3 多態
多態是指同一操作作用于不同的類的實例,不同的類將進行不同的解釋,最后產生不同的執行結果。C#支持兩種多態:編譯時多態和運行時多態。編譯時多態通過重載實現,對于不同重載的成員,系統在編譯時根據傳遞的參數、返回的類型等來決定實現何種操作。運行時多態直到系統運行時才知道實際情況決定何種操作。
簡單來說,通過繼承實現的不同對象調用相同的方法,表現出不同的行為,稱為多態。
【范例14】
本范例演示多態性,Animal對象數組中的不同對象在調用Eat()方法時,表現出不同的行為。實現步驟如下。
(1)創建Animal類,在該類中通過virtual定義一個虛方法,代碼如下。
public class Animal { public virtual void Eat() { Console.WriteLine("動物吃東西..."); } }
在上述代碼中,為Eat()方法添加可選修飾符virtual后變成虛方法,這樣子類在繼承后才可以重寫該方法,從而實現面向對象最重要的特征——多態性。
(2)創建繼承自Animal類的Cat類,在該類中通過override重寫Eat()方法,代碼如下。
public class Cat : Animal { public override void Eat() { Console.WriteLine("小貓咪的食物是魚..."); } }
(3)創建繼承自Animal類的Dog類,該類與Cat類一樣,需要通過override重寫Eat()方法,代碼不再顯示。
(4)向Main()方法中添加代碼,首先定義Animal類型的數組,該數組包含三個元素,通過new實例化不同的對象,最后在for循環中輸出對象的Eat()方法,代碼如下。
static void Main(string[] args) { Animal[] animals = new Animal[3]; animals[0] = new Animal(); animals[1] = new Cat(); animals[2] = new Dog(); for (int i = 0; i < 3; i++) { animals[i].Eat(); } Console.ReadLine(); }
(5)運行Program.cs文件查看輸出結果,內容如下。
動物吃東西…… 小貓咪的食物是魚…… 小狗的食物是骨頭……
多態的實現看起來簡單,但是要完全理解及靈活運行C#的多態機制,也不是一件容易的事情。在范例14中,animals[1] = new Cat()等價于以下代碼:
Cat cat = new Cat();
真正的多態是使用override來實現的,使用override修飾符進行方法重寫,就實現了多態。方法重寫與方法重載不同,重寫是指修飾符、返回值、名稱、參數等完全相同,只是方法中的內容不同而已。需要注意的是,要對一個類中的方法使用override修飾,該類必須從父類中繼承了一個對應的用virtual修飾的虛擬方法,否則編譯器將報錯。
- 大學計算機基礎(第二版)
- Android和PHP開發最佳實踐(第2版)
- 深入理解Django:框架內幕與實現原理
- 信息可視化的藝術:信息可視化在英國
- Learning AWS Lumberyard Game Development
- 數據結構簡明教程(第2版)微課版
- Learning Python Design Patterns(Second Edition)
- C語言程序設計實驗指導 (第2版)
- 持續輕量級Java EE開發:編寫可測試的代碼
- Clojure for Java Developers
- Unity 2017 Game AI Programming(Third Edition)
- 青少年學Python(第2冊)
- Scratch從入門到精通
- Wearable:Tech Projects with the Raspberry Pi Zero
- SQL Server 2014 Development Essentials