您好,登錄后才能下訂單哦!
今天要整理的知識點是C++中有關虛的一切。
包括:虛函數,純虛函數,虛基類,虛繼承...
在基類用virtual聲明成員函數為虛函數。這樣就可以在派生類中重新定義此函數,為它賦予新的功能,并能方便地被調用。在類外定義虛函數時,不必再加virtual。該函數就是虛函數了。虛函數是多態性的基礎,其調用的方式是動態聯編(程序運行時才決定調用基類的還是子類)。虛函數的作用是允許在派生類中重新定義與基類同名的函數,并且可以通過基類指針或引用來訪問基類和派生類中的同名函數,達到多態的目的。
純虛函數只有函數的名字而不具備函數的功能,不能被調用。它只是通知編譯系統:“在這里聲明一個虛函數,留待派生類中定義”。在派生類中對此函數提供定義后,它才能具備函數的功能,可被調用。聲明純虛函數的一般形式是
virtual 函數類型 函數名 (參數表列)=0;
純虛類也稱抽象類,凡是包含純虛函數的類都是抽象類。因為純虛函數是不能被調用的,包含純虛函數的類是無法建立對象的。
抽象類的作用是作為一個類族的共同基類,或者說,為一個類族提供一個公共接口。
這樣做是為了當用一個基類的指針刪除一個派生類的對象時,派生類的析構函數會被調用。
當然,并不是要把所有類的析構函數都寫成虛函數。因為當類里面有虛函數的時候,編譯器會給類添加一個虛函數表,里面來存放虛函數指針,這樣就會增加類的存儲空間。所以,只有當一個類被用來作為基類的時候,才把析構函數寫成虛函數。
可以。
可以,當需要定義一個抽象類,如果其中沒有其他合適的函數,可以把析構函數定義為純虛的。
虛函數的意思就是開啟動態綁定,程序會根據對象的動態類型來選擇要調用的方法。然而在構造函數運行的時候,這個對象的動態類型還不完整,沒有辦法確定它到底是什么類型,故構造函數不能動態綁定。(動態綁定是根據對象的動態類型而不是函數名,在調用構造函數之前,這個對象根本就不存在,它怎么動態綁定?)
在構造函數不要調用虛函數。在基類構造的時候,虛函數是非虛,不會走到派生類中,既是采用的靜態綁定。顯然的是:當我們構造一個子類的對象時,先調用基類的構造函數,構造子類中基類部分,子類還沒有構造,還沒有初始化,如果在基類的構造中調用虛函數,如果可以的話就是調用一個還沒有被初始化的對象,那是很危險的,所以C++中是不可以在構造父類對象部分的時候調用子類的虛函數實現。但是不是說你不可以那么寫程序,你這么寫,編譯器也不會報錯。只是你如果這么寫的話編譯器不會給你調用子類的實現,而是還是調用基類的實現。
在析構函數中也不要調用虛函數。在析構的時候會首先調用子類的析構函數,析構掉對象中的子類部分,然后在調用基類的析構函數析構基類部分,如果在基類的析構函數里面調用虛函數,會導致其調用已經析構了的子類對象里面的函數,這是非常危險的。
虛繼承,就是在被繼承的類前面加上virtual關鍵字,這時被繼承的類稱為虛基類。虛繼承在多重繼承的時可以防止二義性。主要用在如下的菱形繼承:
class A class B1:public virtual A; class B2:public virtual A; class D:public B1,public B2;
為實現動態聯編,編譯器為每個包含虛函數的類創建一個表,稱為vtable,在vtable中,編譯器放置了特定類的虛函數地址,在每個帶有虛函數的類中編譯器會秘密地設置一個虛函數表指針,稱為vptr,指向對象的vtable,通過基類指針做虛函數調用時,也就是多態調用時,編譯器靜態地插入取得這個vptr,并在vtable表種查找函數地址的代碼,這樣就能調用正確的函數。
動態聯編是指在程序執行的時候才將函數實現和函數調用關聯,因此也叫運行時綁定或者晚綁定,動態聯編對函數的選擇不是基于指針或者引用,而是基于對象類型,不同的對象類型將做出不同的編譯結果。C++中一般情況下聯編也是靜態聯編,但是一旦涉及到多態和虛擬函數就必須要使用動態聯編了。
RTTI(Run-Time Type Information)運行時類型檢查的英文縮寫,它提供了運行時確定對象類型的方法,通過RTTI,能夠通過基類的指針或引用來檢索其所指對象的實際類型。c++通過下面兩個操作符提供RTTI:
(1)typeid:返回指針或引用所指對象的實際類型。
(2)dynamic_cast:將基類類型的指針或引用安全的轉換為派生類型的指針或引用。
對于帶虛函數的類,在運行時執行RTTI操作符,返回動態類型信息;對于其他類型,在編譯時執行RTTI,返回靜態類型信息。
眾網友博客
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。