<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>

新聞中心

EEPW首頁(yè) > EDA/PCB > 動(dòng)態(tài)聯(lián)編

動(dòng)態(tài)聯(lián)編

——
作者: 時(shí)間:2007-04-17 來(lái)源: 收藏
動(dòng)態(tài)聯(lián)編

面向對象程序設計的基本觀(guān)點(diǎn)是用程式來(lái)仿真大千世界,這使得它的各種根本特性非常人性化,如封裝、繼承、多態(tài)等等,而虛擬函數就是c++中實(shí)現多態(tài)性的主將。為了實(shí)現多態(tài)性,c++也革命性地提供了動(dòng)態(tài)聯(lián)編(或叫晚捆綁)這一特征。 

  虛擬函數亦是mfc編程的關(guān)鍵所在,mfc編程主要有兩種方法:一是響應各種消息,進(jìn)行對應的消息處理。二就是重載并改寫(xiě)虛擬函數,來(lái)實(shí)現自己的某些要求或改變系統的某些默認處理。 

  虛函數的地位是如此的重要,對它進(jìn)行窮根究底,力求能知其然并知其所以然 對我們編程能力的提高大有好處。下面且聽(tīng)我道來(lái)。 

  多態(tài)性和動(dòng)態(tài)聯(lián)編的實(shí)現過(guò)程分析 

  一、基礎略提(限于篇幅,請參閱相應的c++書(shū)籍): 

  1、多態(tài)性:使用基礎類(lèi)的指針動(dòng)態(tài)調用其派生類(lèi)中函數的特性。 

  2、動(dòng)態(tài)聯(lián)編:在運行階段,才將函數的調用與對應的函數體進(jìn)行連接的方式,又叫運行時(shí)聯(lián)編或晚捆綁。 

  二、過(guò)程描述: 

  1、發(fā)現一個(gè)類(lèi)中有虛函數,會(huì )立即為此類(lèi)生成虛擬函數表 vtable(后面有對vtable的分析)。虛擬函數表的各表項為指向對應虛擬函數的指針。 

  2、編譯器在此類(lèi)中隱含插入一個(gè)指針vptr(對vc編譯器來(lái)說(shuō),它插在類(lèi)的第一個(gè)位置上)。 

  有一個(gè)辦法可以讓你感知這個(gè)隱含指針的存在,雖然你不能在類(lèi)中直接看到它,但你可以比較一下含有虛擬函數時(shí)的類(lèi)的尺寸和沒(méi)有虛擬函數時(shí)的類(lèi)的尺寸,你能夠發(fā)現,這個(gè)指針確實(shí)存在。 

  class cnovirtualfun 
   { 
    private: 
    long lmember; 
    public: 
    long getmembervalue(); 
   } class chavevirtualfun 
   { 
    private: 
     long lmember; 
    public: 
     virtual long getmembervalue(); 
    } 

   cnovirtualfun obj; 
   sizeof(obj) -> == 4; 
   chavevirtualfun obj; 
   sizeof(obj) -> == 8; 

  3、在調用此類(lèi)的構造函數時(shí),在類(lèi)的構造函數中,編譯器會(huì )隱含執行vptr與vtable的關(guān)聯(lián)代碼,將vptr指向對應的vtable。這就將類(lèi)與此類(lèi)的vtable聯(lián)系了起來(lái)。 

  4、在調用類(lèi)的構造函數時(shí),指向基礎類(lèi)的指針此時(shí)已經(jīng)變成指向具體的類(lèi)的this指針,這樣依靠此this指針即可得到正確的vtable,從而實(shí)現了多態(tài)性。在此時(shí)才能真正與函數體進(jìn)行連接,這就是動(dòng)態(tài)聯(lián)編。 
  三、vtable 分析: 

  分析1:虛擬函數表包含此類(lèi)及其父類(lèi)的所有虛擬函數的地址。如果它沒(méi)有重載父類(lèi)的虛擬函數,vtable中對應表項指向其父類(lèi)的此函數。反之,指向重載后的此函數。 

  分析2:虛擬函數被繼承后仍舊是虛擬函數,虛擬函數非常嚴格地按出現的順序在 vtable 中排序,所以確定的虛擬函數對應 vtable 中一個(gè)固定的位置n,n是一個(gè)在編譯時(shí)就確定的常量。所以,使用vptr加上對應的n,就可得到對應函數的入口地址。 

  四、編譯器調用虛擬函數的匯編碼(參考think in c++): 

  push funparam ;先將函數參數壓棧 

  push si ;將this指針壓棧,以確保在當前類(lèi)上操作 

  mov bx,word ptr[si] ;因為vc++編譯器將vptr放在類(lèi)的第一個(gè)位置上,所以bx內為vptr 

  call word ptr[bx+n] ;調用虛擬函數。n = 所調用的虛擬函數在對應 vtable 中的位置 


  純虛函數: 

  一、引入原因: 

  1、為了方便使用多態(tài)特性,我們常常需要在基類(lèi)中定義虛擬函數。 

  2、在很多情況下,基類(lèi)本身生成對象是不合情理的。例如,動(dòng)物作為一個(gè)基類(lèi)可以派生出老虎、孔雀等子類(lèi),但動(dòng)物本身生成對象明顯不合常理。 

  為了解決上述問(wèn)題,引入了純虛函數的概念,將函數定義為純虛函數(方法:virtual returntype function()= 0;),則編譯器要求在派生類(lèi)中必須予以重載以實(shí)現多態(tài)性。同時(shí)含有純虛擬函數的類(lèi)稱(chēng)為抽象類(lèi),它不能生成對象。這樣就很好地解決了上述兩個(gè)問(wèn)題。 

  二、純虛函數實(shí)質(zhì): 

  1、類(lèi)中含有純虛函數則它的vtable表不完全,有一個(gè)空位,所以,不能生成對象(編譯器絕對不允許有調用一個(gè)不存在函數的可能)。在它的派生類(lèi)中,除非重載這個(gè)函數,否則,此派生類(lèi)的vtable表亦不完整,亦不能生成對象,即它也成為一個(gè)純虛基類(lèi)。 


  虛函數與構造、析構函數: 

  1、構造函數本身不能是虛擬函數;并且虛機制在構造函數中不起作用(在構造函數中的虛擬函數只會(huì )調用它的本地版本)。 

  想一想,在基類(lèi)構造函數中使用虛機制,則可能會(huì )調用到子類(lèi),此時(shí)子類(lèi)尚未生成,有何后果???。 

  2、析構函數本身常常要求是虛擬函數;但虛機制在析構函數中不起作用。 

  若類(lèi)中使用了虛擬函數,析構函數一定要是虛擬函數,比如使用虛擬機制調用delete,沒(méi)有虛擬的析構函數,怎能保證delete的是你希望delete的對象。 

  虛機制也不能在析構函數中生效,因為可能會(huì )引起調用已經(jīng)被delete掉的類(lèi)的虛擬函數的問(wèn)題。 

  對象切片: 

  向上映射(子類(lèi)被映射到父類(lèi))的時(shí)候,會(huì )發(fā)生子類(lèi)的vtable 完全變成父類(lèi)的vtable的情況。這就是對象切片。 

  原因:向上映射的時(shí)候,接口會(huì )變窄,而編譯器絕對不允許有調用一個(gè)不存在函數的可能,所以,子類(lèi)中新派生的虛擬函數的入口在vtable中會(huì )被強行“切”掉,從而出現上述情況。 

  虛擬函數使用的缺點(diǎn) 

  優(yōu)點(diǎn)講了一大堆,現在談一下缺點(diǎn),虛函數最主要的缺點(diǎn)是執行效率較低,看一看虛擬函數引發(fā)的多態(tài)性的實(shí)現過(guò)程,你就能體會(huì )到其中的原因。


評論


相關(guān)推薦

技術(shù)專(zhuān)區

關(guān)閉
国产精品自在自线亚洲|国产精品无圣光一区二区|国产日产欧洲无码视频|久久久一本精品99久久K精品66|欧美人与动牲交片免费播放
<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>