C++面向對象------多態

1、虛函數、覆蓋、多態安全

  虛函數:在定義時添加virtual關鍵字的成員函數,叫虛函數函數

  覆蓋:在子類中實現與父類中虛函數相同的函數,那麼子類中的成員函數會覆蓋父類中的成員函數this

    不一樣於隱藏,隱藏是在父子類之間名字相同的標識符,只要不夠成覆蓋,就是隱藏。子類會隱藏父類中的同名函數spa

  多態:若是子類中的成員函數對父類中的成員函數進行了覆蓋,那麼當一個指向子類的父類指針或引用了子類的父類引用,在調用此同名函數時會調用子類中的函數,而不是父類中的虛函數,這種語法現象叫多態。設計

  多態的意義在於同一種類發出同一種調用而產生不一樣的反映指針

 

2、覆蓋、重載、隱藏的條件對象

  覆蓋(重寫):繼承

    a、不在同一做用域,分別在基類和派生類接口

    b、函數名、參數、返回值相同內存

    c、基類函數必須有virtual關鍵字

    d、訪問修飾符能夠不一樣

    

  重載:

    a、在同一做用域下

    b、函數名相同,參數不一樣

    c、返回值能夠不一樣

  

  隱藏:

    a、在不一樣做用域中

    b、函數名相同

    c、在基類和派生類中只要不構成覆蓋就是隱藏

 

3、多態的條件

   一、派生類必須重寫基類的虛函數。

   二、經過基類指針或引用調用基類的虛函數(該虛函數派生類必需要重寫)

   三、當指針或引用已經構成多態時,此時調用成員所傳的this指針再調用成員函數時也構成多態

   四、在子類的構造函數執行前會先調用父類的構造函數,若是調用被覆蓋的虛函數,因爲子類還沒構造完成,所以只能是調用父類中的虛函數構造函數在進入函數體執行時,類中看得見的資源已經所有構造完成

   五、在子類的析構函數執行完成後會再調用父類的析構函數,若是調用被覆蓋的虛函數,因爲子類已經開始析構完成已經不能算是完整的子類了,所以只能調用父類中的虛函數

 

4、純虛函數和抽象類
  一、純虛函數
    class A
    {
      public:
      virtual void test(void) = 0;
      virtual void test(void) const = 0;
    };
    a、純虛函數不須要被實現,若是非要實現也不能在類中,必需要在類外(虛函數)

    b、純虛函數若是想調用必須在子類中覆蓋,而後以多態的方式調用


  二、抽象類

    成員函數中有純虛函數的叫抽象類,這種類不能建立對象。

    若是子類繼承了抽象類,則必須把父類中的純虛函數覆蓋了,不然他也變成了抽象類不能被實例化

    所以抽象類只能以指針或引用的方式指向子類來調用非純虛函數


  三、純抽象類

    全部的成員函數都是純虛函數,這種類叫純抽象類

    面向對象的四大特性:抽象、封裝、繼承、多態

    純抽象類是類封裝的過程,同時抽象類也能夠當作一個統一的接口

6、虛函數表

    一、什麼是虛函數表,當一個類中有虛函數時,編譯器會爲這個函數分配一個專門記錄這些的虛函數表,在類中會有一個隱藏的指針成員指向這張表

    二、如何證實這張表存在

      有虛函數的類會比沒有虛函數的類(相同的)多4字節,還會添加補齊和對其

    三、一個類只有一張虛函數表,全部對象共享一張虛函數表

    四、通常對象的前4字節是指向虛函數表的指針


7、動態類型綁定(多態)
  一、當使用父類指針或引用指向子類時,編譯器並無當即生成調用函數的指針,而是生成了一段代碼,用於檢查指針指向的真正的對象是什麼類型

  二、在代碼真正運行時才經過對象的指針找到指向虛函數的成員指針

  三、再經過成員指針訪問到虛函數表,再從中找到調用的函數地址

  四、使用多態會產生額外的一些代碼和調用,所以使用多態會下降代碼的執行速度



9、虛析構
  一、若是經過父類指針或引用指向子類對象,當使用delete釋放對象時,此時只能調用父類的析構函數,若是子類中使用new/malloc申請了內存資源,那麼將致使內存泄漏

  二、解決方法就是把父類的析構函數設置爲虛函數

  三、在設計類時若是析構函數什麼都須要作,編譯器也會生成一個空的析構函數,但這樣會讓繼承它的子類會有安全隱患

  四、最好把全部的析構函數都設置爲虛函數

相關文章
相關標籤/搜索