從匯編的角度了解C++原理——虛函數-創新互聯

文章目錄
  • 1、虛函數
    • 1.1、虛函數儲存結構
    • 1.2、子類重寫虛函數
    • 1.3、在棧上調用虛函數
    • 1.4、在堆上調用虛函數(通過指針調用,多態)

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

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

其它文章:
從匯編的角度了解C++原理——類的儲存結構和函數調用
從匯編的角度了解C++原理——new和malloc的區別
從匯編的角度了解C++原理——虛函數

1、虛函數 1.1、虛函數儲存結構

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

main:
        sub     rsp, 56                             
        lea     rcx, [rsp+20H]                    
        call    ??0A@@QEAA@XZ      				//調用構造函數                  
        mov     eax, 4294967295                  
        add     rsp, 56                                
        ret                                             
        
??0A@@QEAA@XZ:									//調用A類的構造函數
        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個字節的位置定義d1變量       
        mov     rax, qword [rsp+8H]                     
        ret                                                           

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

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

1.2、子類重寫虛函數

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

反匯編

main:
        sub     rsp, 56                             
        lea     rcx, [rsp+20H]                       
        call    ??0B@@QEAA@XZ          		//調用B類構造                
        mov     eax, 4294967295                        
        add     rsp, 56                                
        ret                                             
        
??0A@@QEAA@XZ:								//A類構造函數
        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類構造函數
        mov     qword [rsp+8H], rcx                
        sub     rsp, 40                             
        mov     rcx, qword [rsp+30H]               
        call    ??0A@@QEAA@XZ    			//調用A類構造                   
        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實現的func2          
        dq ?func3@A@@UEAAXXZ                //A::func3                        

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

1.3、在棧上調用虛函數

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

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

在棧上調用方法時,因為類型是確定的,所以編譯器在編譯階段就會找到對應的函數去調用,調用過程與普通方法一樣。

1.4、在堆上調用虛函數(通過指針調用,多態)

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

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指向對象          
        jmp     ?_002                       //跳到?_002            

?_001:  mov     qword [rsp+30H], 0   
                  
?_002:  mov     rax, qword [rsp+30H]                   
        mov     qword [rsp+38H], rax        //rsp+38H指向對象         
        mov     rax, qword [rsp+38H]        //rax指向對象           
        mov     qword [rsp+20H], rax        //rsp+20H指向對象       
        mov     rcx, qword [rsp+20H]        //rcx指向對象          
        call    ?func1@A@@QEAAXXZ           //調用A::func1       
        mov     rax, qword [rsp+20H]                 
        mov     rax, qword [rax]            //取虛表        
        mov     rcx, qword [rsp+20H]                   
        call    near [rax]                  //執行虛表第一個函數,即B::func2           
        mov     rax, qword [rsp+20H]                   
        mov     rax, qword [rax]                       
        mov     rcx, qword [rsp+20H]                
        call    near [rax+8H]             	//執行虛表第二個函數,即A::func3             
        mov     eax, 4294967295                         
        add     rsp, 72                               
        ret                                          
        
??_7B@@6B@:                                           
        dq ?func2@B@@UEAAXXZ                        
        dq ?func3@A@@UEAAXXZ                         

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

你是否還在尋找穩定的海外服務器提供商?創新互聯www.cdcxhl.cn海外機房具備T級流量清洗系統配攻擊溯源,準確流量調度確保服務器高可用性,企業級服務器適合批量采購,新人活動首月15元起,快前往官網查看詳情吧

分享文章:從匯編的角度了解C++原理——虛函數-創新互聯
分享路徑:http://m.kartarina.com/article42/cdcoec.html

成都網站建設公司_創新互聯,為您提供定制網站營銷型網站建設App開發服務器托管用戶體驗品牌網站設計

廣告

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

成都定制網站網頁設計
主站蜘蛛池模板: 亚洲aⅴ无码专区在线观看| 国产成年无码久久久免费| 精品三级AV无码一区| 亚洲精品偷拍无码不卡av| 少妇无码AV无码专区线| 免费人妻无码不卡中文字幕18禁| 亚洲AV无码专区亚洲AV伊甸园| 亚洲日韩精品无码专区加勒比| 国内精品人妻无码久久久影院| 无码爆乳护士让我爽| yy111111电影院少妇影院无码| 人妻少妇伦在线无码专区视频| 九九久久精品无码专区| 国产精品亚洲а∨无码播放不卡| 色窝窝无码一区二区三区| 国产亚洲?V无码?V男人的天堂 | 精品无码成人片一区二区| 无码国产乱人伦偷精品视频| 亚洲AV无码乱码精品国产| 亚洲国产成人无码av在线播放| 国模吧无码一区二区三区| 无码av天天av天天爽| 在线观看无码AV网址| 最新国产AV无码专区亚洲| 亚洲Av无码国产情品久久| 国产成年无码v片在线| 老司机无码精品A| 亚洲中文字幕无码中文字| 无码精品一区二区三区在线| 中文字幕精品无码久久久久久3D日动漫| 无码国产精成人午夜视频不卡| 中文字幕乱偷无码av先锋蜜桃| 久久亚洲精品无码VA大香大香| 国产成A人亚洲精V品无码| 伊人久久精品无码二区麻豆| 国产成人无码区免费内射一片色欲 | 日韩精品无码人成视频手机 | 免费看成人AA片无码视频羞羞网| 国产午夜鲁丝无码拍拍| 无码av免费网站| 日韩午夜福利无码专区a|