單繼承虛函式例子
class point
virtual
float y() const
virtual
float z() const
// ...
protected:
point( float x = 0.0 );
float _x; };
class point2d : public point
~point2d();
// overridden base class virtual functions
point2d& mult( float );
float y() const
// ... other operations ...
protected:
float _y; };
class point3d: public point2d
~point3d();
// overridden base class virtual functions
point3d& mult( float );
float z() const
// ... other operations ...
protected:
float _z; };
vtable和vptr結構
虛函式的實現是通過vtable和vptr。每乙個帶有虛函式的類都有乙個vtable,在編譯器生成,每乙個帶有虛函式的類例項都有乙個vptr,該類例項vptr指向該類的vtable,在執行期生成。
如圖左部的類例項記憶體結構,編譯器為之生成__vptr__point的指標,指向該類的vtable。
vtable的結構是乙個函式指標陣列,陣列的每個元素是乙個函式指標,指向該類虛函式的位址。因為基類point的point::mult()為純虛函式,因此point對應的mult函式指標指向乙個pure_virtual_called(),丟擲呼叫純虛函式錯誤。
如圖vtable所示,point類和其子類的析構函式均在vtable[1],mult在vtable[2],y在vtable[3],z在vtable[4]。如果point2d增加point2d自己的虛函式,同時point3d繼承point2d的虛函式,他們相同的虛函式介面同樣對應於相同的vtable陣列下標,如vtable[5],此由編譯器保證,因而編譯器對於虛函式介面能將其轉換為函式指標陣列的下標。
故,當呼叫
ptr->z();
編譯器實際呼叫的是:
( *ptr->vptr[ 4 ] )( ptr );
從而可以找到ptr實際指向的vtable中的虛函式呼叫位址。
虛函式系統開銷
為了實現虛函式,編譯器產生的操作包括:
編譯期,為每乙個類增加乙個vtable函式指標陣列,並使其指向正確的虛函式實現。
執行期,在類的建構函式中,為每乙個類例項增加乙個vptr,指向該類的vtable。
編譯器,將虛函式呼叫編譯為函式指標的呼叫。
執行期,在虛函式呼叫時,通過指向vtable和呼叫函式的index,查詢函式指標(查詢效率為陣列隨機訪問,常數時間),呼叫虛函式。
由分析得,虛函式開銷主要在編譯期的vtable函式指標陣列的構造,而執行期的函式指標查詢不是效能瓶頸。同時,乙個帶虛函式的基類無論有多少個孩子類,並不會降低虛函式效能,而如果類的繼承層次太深,底層類例項的建構函式則需要為類繼承層次的每一層父類初始化vptr,效率降低。
虛函式系統效能測試
void
cross_product( const pt3d &pa, const pt3d &pb )
main()
optimized non-optimized
inline member 0.08 4.70
nonstatic member 4.43 6.13
virtual member
cc 4.76 6.90
ncc 4.63 7.72
cc和ncc是比較的兩個編譯器版本,對於上述計算函式的
測試,虛函式的呼叫開銷主要是3.4虛表查詢,
虛函式呼叫損失了
4% 到
11%的執行時間。相對於io操作,可以忽略。
參考文獻
inside the c++ object model, by stanley b. lippman
C 虛指標實現及效率
單繼承虛函式例子 classpoint virtual float y const virtual float z const protected point float x 0.0 float x classpoint2d public point point2d overridden base ...
C 虛函式實現 虛函式表 虛表指標
內聯函式 編譯時展開的,虛函式是為了實現多型,是動態行為,兩者是矛盾的。內聯函式展開就不存在了,也就不存在函式位址了,無法呼叫。但是,由於inline只是向編譯器建議,所以編譯器不會讓inline和virtual同時起作用,所以也不會報錯。建構函式 虛函式使用虛指標呼叫函式,呼叫建構函式之前沒有構造...
c 虛函式實現與this指標
我們知道當我們sizeof 乙個類的時候,類的成員函式是不計算在物件的大小的裡的,這是為什麼呢?因為類的成員函式不是屬於某乙個物件的,而是類的所有物件所共享的,就像static變數那樣。如果虛函式和普通成員函式一樣,那麼我們就不能通過指向子類的基類指標來引用子類的方法了,因為我們將不知道呼叫哪個方法...