官术网_书友最值得收藏!

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修飾的虛擬方法,否則編譯器將報錯。

主站蜘蛛池模板: 修武县| 郑州市| 德令哈市| 文登市| 保定市| 招远市| 容城县| 杭锦后旗| 张家港市| 江门市| 普宁市| 平原县| 新干县| 瑞安市| 绥滨县| 婺源县| 宜春市| 太仓市| 息烽县| 太仓市| 涪陵区| 会昌县| 酒泉市| 通化市| 南郑县| 白城市| 亚东县| 萍乡市| 肇州县| 惠水县| 铁岭县| 南城县| 陆川县| 雷山县| 板桥市| 繁昌县| 民乐县| 安乡县| 时尚| 开平市| 桂林市|