C++的三大特性封裝、繼承和多態


 

封裝可以使得代碼模塊化,繼承可以擴展已存在的代碼,他們的目的都是為了代碼重用。而多態的目的則是為了接口重用

  • 封裝:封裝是在設計類的一個基本原理,是將抽象得到的數據和行為(或功能)相結合,形成一個有機的整體,也就是將數據與對數據進行的操作進行有機的結合,形成“類”,其中數據和函數都是類的成員。

  • 繼承:如果一個類別B“繼承自”另一個類別A,就把這個B稱為“A的子類”,而把A稱為“B的父類別”也可以稱“A是B的超類”。繼承可以使得子類具有父類別的各種屬性和方法,而不需要再次編寫相同的代碼。在令子類別繼承父類別的同時,可以重新定義某些屬性,並重寫某些方法,即覆蓋父類別的原有屬性和方法,使其獲得與父類別不同的功能。

    1. 訪問權限

      • public: 父類對象內部、父類對象外部、子類對象內部、子類對象外部都可以訪問。
      • protected:父類對象內部、子類對象內部可以訪問,父類對象外部、子類對象外部都不可訪問。
      • private:父類對象內部可以訪問,其他都不可以訪問。

      |訪問對象|public|protected|private|
      |-|-|-|-|
      |父類|可見|可見|可見|
      |子類|可見|可見|不可見|
      |父類外部|可見|不可見|不可見|
      |子類外部|可見|不可見|不可見|

    2. 繼承方式
      ps.三種繼承方式不影響子類對父類的訪問權限,子類對父類只看父類的訪問控制權。繼承方式是為了控制子類(也稱派生類)的調用方(也叫用戶)對父類(也稱基類)的訪問權限。public、protected、private三種繼承方式,相當於把父類的public訪問權限在子類中變成了對應的權限。 如protected繼承,把父類中的public成員在本類中變成了protected的訪問控制權限;private繼承,把父類的public成員和protected成員在本類中變成了private訪問控制權。

      ps.友元是類級別的,不存在繼承的問題。

  • 多態:多態性可以簡單地概括為“一個接口,多種方法”,程序在運行時才決定調用的函數,它是面向對象編程領域的核心概念。多態(polymorphism),字面意思多種形狀。

    1. 靜態多態:靜態多態也稱為靜態綁定或早綁定。編譯器在編譯期間完成的,編譯器根據函數實參的類型(可能會進行隱式類型轉換),可推斷出要調用那個函數,如果有對應的函數就調用該函數,否則出現編譯錯誤。

      • 函數重載

        編譯器根據函數不同的參數表,對同名函數的名稱做修飾,然后這些同名函數就成了不同的函數(至少對於編譯器來說是這樣的)。函數的調用,在編譯器間就已經確定了,是靜態的。也就是說,它們的地址在編譯期就綁定了(早綁定)。

      • 泛型編程

        泛型編程就是指編寫獨立於特定類型的代碼,泛型在C++中的主要實現為模板函數和模板類。
        泛型的特性:

          1. 函數模板並不是真正的函數,它只是C++編譯生成具體函數的一個模子。
          1. 函數模板本身並不生成函數,實際生成的函數是替換函數模板的那個函數,比如上例中的add(sum1,sum2),這種替換是編譯期就綁定的。
          3. 函數模板不是只編譯一份滿足多重需要,而是為每一種替換它的函數編譯一份。
          4. 函數模板不允許自動類型轉換。
          5. 函數模板不可以設置默認模板實參。比如template <typename T=0>不可以。
        
    2. 動態多態
      c++的動態多態是基於虛函數的。對於相關的對象類型,確定它們之間的一個共同功能集,然后在基類中,把這些共同的功能聲明為多個公共的虛函數接口。各個子類重寫這些虛函數,以完成具體的功能。客戶端的代碼(操作函數)通過指向基類的引用或指針來操作這些對象,對虛函數的調用會自動綁定到實際提供的子類對象上去。

    3. 宏多態(?)
      帶變量的宏可以實現一種初級形式的靜態多態:

      #include <iostream>
      #include <string>
      
      // 定義泛化記號:宏ADD
      #define ADD(A, B) (A) + (B);
      
      int main()
      {
          int i1(1), i2(2);
          std::string s1("Hello, "), s2("world!");
          int i = ADD(i1, i2);                        // 兩個整數相加
          std::string s = ADD(s1, s2);                // 兩個字符串“相加”
          std::cout << "i = " << i << "/n";
          std::cout << "s = " << s << "/n";
      }
      
    4. 動態多態和靜態多態的比較

      1. 靜態多態
        • 優點:
          1. 由於靜多態是在編譯期完成的,因此效率較高,編譯器也可以進行優化;
          2. 有很強的適配性和松耦合性,比如可以通過偏特化、全特化來處理特殊類型;
          3. 最重要一點是靜態多態通過模板編程為C++帶來了泛型設計的概念,比如強大的STL庫。
        • 缺點:
          1. 由於是模板來實現靜態多態,因此模板的不足也就是靜多態的劣勢,比如調試困難、編譯耗時、代碼膨脹、編譯器支持的兼容性不能夠處理異質對象集合
      2. 動態多態
        • 優點:
          1. OO設計,對是客觀世界的直覺認識;
          2. 實現與接口分離,可復用
          3. 處理同一繼承體系下異質對象集合的強大威力
        • 缺點:
          1. 運行期綁定,導致一定程度的運行時開銷;
          2. 編譯器無法對虛函數進行優化
          3. 笨重的類繼承體系,對接口的修改影響整個類層次;
      3. 不同點:
        • 本質不同,早晚綁定。靜態多態在編譯期決定,由模板具現完成,而動態多態在運行期決定,由繼承、虛函數實現;
        • 動態多態中接口是顯式的,以函數簽名為中心,多態通過虛函數在運行期實現,靜態多台中接口是隱式的,以有效表達式為中心,多態通過模板具現在編譯期完成
      4. 相同點:
        • 都能夠實現多態性,靜態多態/編譯期多態、動態多態/運行期多態;
        • 都能夠使接口和實現相分離,一個是模板定義接口,類型參數定義實現,一個是基類虛函數定義接口,繼承類負責實現;

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM