程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> 更多關於編程 >> 什麼是虛函數,C++虛函數講解

什麼是虛函數,C++虛函數講解

編輯:更多關於編程

      虛函數是在類中被聲明為virtual的成員函數,當編譯器看到通過指針或引用調用此類函數時,對其執行晚綁定,即通過指針(或引用)指向的類的類型信息來決定該函數是哪個類的。通常此類指針或引用都聲明為基類的,它可以指向基類或派生類的對象。

      多態指同一個方法根據其所屬的不同對象可以有不同的行為。

      下面來看一個例子:

    什麼是虛函數,C++虛函數講解 三聯

      程序運行輸出結果: 8, 12

      為什麼Base 對象的大小是8個字節而不是4個字節,為什麼Derived 對象的大小是12個字節而不是8個字節,多出來的4個字節做什麼用呢?和多態的實現有什麼關系?

      每一個有虛函數的類(或有虛函數的類的派生類)都有一個虛函數表,該類的任何對象中都放著虛函數表的指針。虛函數表中列出了該類的虛函數地址。多出來的4個字節就是用來放虛函數表的地址的。

      每當創建一個包含虛函數的類或者從一個有虛函數的基類中派生一個類時,編譯器就為這個類創建一個VTABLE,在這個表中,放置了在這個類中或 它的基類中所有聲明為virtual的虛函數的地址。然後編譯器在這個類中放置VPTR指向相應的VTABLE。VPTR必須在構造函數中被初始化,在 VPTR初始化之前,絕對不能調用虛函數。所有的基類對象或者從基類派生出的對象的VPTR都在各自對象的相同位置。所有的VTABLE有相同的順序,不 管何種類型的對象。

      C++的函數調用與C一樣,都是從右向左進棧的,其間,對象的首地址也即this指針的值被壓入棧,正因為調用每個成員函數時this都必須作 為參數壓進棧,所以成員函數知道它工作在哪個特殊對象上。這樣,我們總能看到,在成員函數調用之前壓棧的次數等於參數個數加一(除了STatic成員函 數,它沒有this)。

      純虛函數 :

      抽象類就是在類的聲明前面加上virtual關鍵字,為了防止誤用抽象類,可以在抽象類中定義純虛函數,例如virtual void x()=0;

      這樣做,等於告訴編譯器在VTABLE中為函數保留一個間隔,但在這個特定間隔不放地址,只要有一個純虛函數,則VTABLE就是不完全的,包含純虛函數的類稱為純抽象基類。

      虛函數是C++中用於實現多態(polymorphism)的機制。核心理念就是通過基類訪問派生類定義的函數。假設我們有下面的類層次:

    什麼是c++虛函數

      那麼,在使用的時候,我們可以:

      A * a = new B();

      a->foo(); // 在這裡,a雖然是指向A的指針,但是被調用的函數(foo)卻是B的!

      這個例子是虛函數的一個典型應用,通過這個例子,也許你就對虛函數有了一些概念。它虛就虛在所謂“推遲聯編”或者“動態聯編”上,一個類函數的 調用並不是在編譯時刻被確定的,而是在運行時刻被確定的。由於編寫代碼的時候並不能確定被調用的是基類的函數還是哪個派生類的函數,所以被成為“虛”函 數。

      如下聲明表示一個函數為純虛函數:

      class A

      {

      public:

      virtual void foo()=0; // =0標志一個虛函數為純虛函數

      };

      一個函數聲明為純虛後,純虛函數的意思是:我是一個抽象類!不要把我實例化!純虛函數用來規范派生類的行為,實際上就是所謂的“接口”。它告訴使用者,我的派生類都會有這個函數。

     

    1. 上一頁:
    2. 下一頁:
    Copyright © 程式師世界 All Rights Reserved