從匯編的角度了解C++原理——虛函數(shù)-創(chuàng)新互聯(lián)

文章目錄
  • 1、虛函數(shù)
    • 1.1、虛函數(shù)儲存結(jié)構(gòu)
    • 1.2、子類重寫虛函數(shù)
    • 1.3、在棧上調(diào)用虛函數(shù)
    • 1.4、在堆上調(diào)用虛函數(shù)(通過指針調(diào)用,多態(tài))

本文用到的反匯編工具是objconv,使用方法可以看我另一篇文章https://blog.csdn.net/weixin_45001971/article/details/128660642。

成都創(chuàng)新互聯(lián)公司自2013年創(chuàng)立以來,是專業(yè)互聯(lián)網(wǎng)技術(shù)服務(wù)公司,擁有項目成都網(wǎng)站設(shè)計、成都做網(wǎng)站、外貿(mào)網(wǎng)站建設(shè)網(wǎng)站策劃,項目實(shí)施與項目整合能力。我們以讓每一個夢想脫穎而出為使命,1280元府谷做網(wǎng)站,已為上家服務(wù),為府谷各地企業(yè)和個人服務(wù),聯(lián)系電話:18980820575

其它文章:
從匯編的角度了解C++原理——類的儲存結(jié)構(gòu)和函數(shù)調(diào)用
從匯編的角度了解C++原理——new和malloc的區(qū)別
從匯編的角度了解C++原理——虛函數(shù)

1、虛函數(shù) 1.1、虛函數(shù)儲存結(jié)構(gòu)

在這里插入圖片描述
反匯編。

main:
        sub     rsp, 56                             
        lea     rcx, [rsp+20H]                    
        call    ??0A@@QEAA@XZ      				//調(diào)用構(gòu)造函數(shù)                  
        mov     eax, 4294967295                  
        add     rsp, 56                                
        ret                                             
        
??0A@@QEAA@XZ:									//調(diào)用A類的構(gòu)造函數(shù)
        mov     qword [rsp+8H], rcx                  
        mov     rax, qword [rsp+8H]                    
        lea     rcx, [rel ??_7A@@6B@]           //獲取虛表??_7A@@6B@的地址
        mov     qword [rax], rcx                //把虛表地址放在對象的頭部      
        mov     rax, qword [rsp+8H]                    
        mov     dword [rax+8H], 10              //在對象首地址偏移8個字節(jié)的位置定義d1變量       
        mov     rax, qword [rsp+8H]                     
        ret                                                           

??_7A@@6B@:                     				//A類虛表                       
        dq ?func2@A@@UEAAXXZ                    //虛函數(shù)func2     

以上例的匯編代碼可以得出帶虛函數(shù)的類的儲存結(jié)構(gòu)如下圖所示。
在這里插入圖片描述
帶有虛函數(shù)的對象的頭部會放置8個字節(jié)大小的虛表地址,有了虛表之后的對象會以8個字節(jié)為單位去對齊,如上例中的A類,如果沒有虛函數(shù),它的大小為4個字節(jié),而加了虛函數(shù)之后,大小變?yōu)榱?6個字節(jié)。

1.2、子類重寫虛函數(shù)

在代碼中添加A的子類B,重寫func2方法。
在這里插入圖片描述

反匯編

main:
        sub     rsp, 56                             
        lea     rcx, [rsp+20H]                       
        call    ??0B@@QEAA@XZ          		//調(diào)用B類構(gòu)造                
        mov     eax, 4294967295                        
        add     rsp, 56                                
        ret                                             
        
??0A@@QEAA@XZ:								//A類構(gòu)造函數(shù)
        mov     qword [rsp+8H], rcx                  
        mov     rax, qword [rsp+8H]                     
        lea     rcx, [rel ??_7A@@6B@]     	//把A類虛表的地址放在頭部              
        mov     qword [rax], rcx                      
        mov     rax, qword [rsp+8H]                   
        mov     dword [rax+8H], 10                  
        mov     rax, qword [rsp+8H]           
        ret                                             

??0B@@QEAA@XZ:								//B類構(gòu)造函數(shù)
        mov     qword [rsp+8H], rcx                
        sub     rsp, 40                             
        mov     rcx, qword [rsp+30H]               
        call    ??0A@@QEAA@XZ    			//調(diào)用A類構(gòu)造                   
        mov     rax, qword [rsp+30H]             
        lea     rcx, [rel ??_7B@@6B@]       //把B類虛表的地址放在頭部           
        mov     qword [rax], rcx                    
        mov     rax, qword [rsp+30H]                   
        add     rsp, 40                                 
        ret                                           
       
??_7A@@6B@:                         		//A類虛表                        
        dq ?func2@A@@UEAAXXZ                //A::func2                             
        dq ?func3@A@@UEAAXXZ                //A::func3      
             
??_7B@@6B@:                                 //B類虛表                       
        dq ?func2@B@@UEAAXXZ                //B::func2,被替換為了B實(shí)現(xiàn)的func2          
        dq ?func3@A@@UEAAXXZ                //A::func3                        

從該例中我們可以看到,父類有虛函數(shù)時,不光它自己有一張?zhí)摫?,它的子子孫孫都會各帶有一個自己的虛表,子類重寫虛函數(shù)時,會把子類實(shí)現(xiàn)的函數(shù)指針替換上虛表,把原先父類的函數(shù)指針覆蓋掉。

1.3、在棧上調(diào)用虛函數(shù)

在main里添加方法的調(diào)用。
在這里插入圖片描述
反匯編。

main:
        sub     rsp, 56                               
        lea     rcx, [rsp+20H]                         
        call    ??0B@@QEAA@XZ                        
        lea     rcx, [rsp+20H]                        
        call    ?func1@A@@QEAAXXZ   		//調(diào)用A::func1                 
        lea     rcx, [rsp+20H]                        
        call    ?func2@B@@UEAAXXZ   		//調(diào)用B::func2                       
        lea     rcx, [rsp+20H]                         
        call    ?func3@A@@UEAAXXZ   		//調(diào)用A::func3                         
        mov     eax, 4294967295                         
        add     rsp, 56                                
        ret  

在棧上調(diào)用方法時,因?yàn)轭愋褪谴_定的,所以編譯器在編譯階段就會找到對應(yīng)的函數(shù)去調(diào)用,調(diào)用過程與普通方法一樣。

1.4、在堆上調(diào)用虛函數(shù)(通過指針調(diào)用,多態(tài))

修改例程如下。
在這里插入圖片描述
反匯編

main:
        sub     rsp, 72                                
        mov     ecx, 16                                
        call    ??2@YAPEAX_K@Z                         
        mov     qword [rsp+28H], rax                   
        cmp     qword [rsp+28H], 0                    
        jz      ?_001                                 
        mov     rcx, qword [rsp+28H]		//定義指針b                   
        call    ??0B@@QEAA@XZ                       
        mov     qword [rsp+30H], rax        //rsp+30H指向?qū)ο?         
        jmp     ?_002                       //跳到?_002            

?_001:  mov     qword [rsp+30H], 0   
                  
?_002:  mov     rax, qword [rsp+30H]                   
        mov     qword [rsp+38H], rax        //rsp+38H指向?qū)ο?        
        mov     rax, qword [rsp+38H]        //rax指向?qū)ο?          
        mov     qword [rsp+20H], rax        //rsp+20H指向?qū)ο?      
        mov     rcx, qword [rsp+20H]        //rcx指向?qū)ο?         
        call    ?func1@A@@QEAAXXZ           //調(diào)用A::func1       
        mov     rax, qword [rsp+20H]                 
        mov     rax, qword [rax]            //取虛表        
        mov     rcx, qword [rsp+20H]                   
        call    near [rax]                  //執(zhí)行虛表第一個函數(shù),即B::func2           
        mov     rax, qword [rsp+20H]                   
        mov     rax, qword [rax]                       
        mov     rcx, qword [rsp+20H]                
        call    near [rax+8H]             	//執(zhí)行虛表第二個函數(shù),即A::func3             
        mov     eax, 4294967295                         
        add     rsp, 72                               
        ret                                          
        
??_7B@@6B@:                                           
        dq ?func2@B@@UEAAXXZ                        
        dq ?func3@A@@UEAAXXZ                         

從該例可以看到,通過指針來調(diào)用函數(shù)時。
如果是普通函數(shù),編譯器會直接根據(jù)指針類型,找到對應(yīng)的的方法,而不是根據(jù)對象本身的類型,如本例中B類也實(shí)現(xiàn)了func1方法,但通過A類指針調(diào)用時,寫到匯編里的時A::func1。
如果是虛函數(shù),編譯器不會根據(jù)名字來查找函數(shù),而是讓匯編代碼通過虛表中的偏移量來調(diào)用,如本例中,b指針執(zhí)行了func2和func3,這兩個函數(shù)都沒有被直接調(diào)用,而是以“call near [rax + 偏移量]”的形式調(diào)用了,這也是C++中父類指針指向子類對象的多態(tài)的實(shí)現(xiàn)原理。

你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級服務(wù)器適合批量采購,新人活動首月15元起,快前往官網(wǎng)查看詳情吧

分享文章:從匯編的角度了解C++原理——虛函數(shù)-創(chuàng)新互聯(lián)
分享路徑:http://muchs.cn/article42/cdcoec.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供定制網(wǎng)站、營銷型網(wǎng)站建設(shè)App開發(fā)、服務(wù)器托管、用戶體驗(yàn)、品牌網(wǎng)站設(shè)計

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

成都定制網(wǎng)站網(wǎng)頁設(shè)計