1. <ul id="0c1fb"></ul>

      <noscript id="0c1fb"><video id="0c1fb"></video></noscript>
      <noscript id="0c1fb"><listing id="0c1fb"><thead id="0c1fb"></thead></listing></noscript>

      99热在线精品一区二区三区_国产伦精品一区二区三区女破破_亚洲一区二区三区无码_精品国产欧美日韩另类一区

      RELATEED CONSULTING
      相關咨詢
      選擇下列產(chǎn)品馬上在線溝通
      服務時間:8:30-17:00
      你可能遇到了下面的問題
      關閉右側(cè)工具欄

      新聞中心

      這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
      c++中的虛函數(shù)

      本篇內(nèi)容主要講解“c++中的虛函數(shù)”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“c++中的虛函數(shù)”吧!

      創(chuàng)新互聯(lián)是一家專業(yè)的成都網(wǎng)站建設公司,我們專注網(wǎng)站設計制作、網(wǎng)站設計、網(wǎng)絡營銷、企業(yè)網(wǎng)站建設,友情鏈接1元廣告為企業(yè)客戶提供一站式建站解決方案,能帶給客戶新的互聯(lián)網(wǎng)理念。從網(wǎng)站結(jié)構(gòu)的規(guī)劃UI設計到用戶體驗提高,創(chuàng)新互聯(lián)力求做到盡善盡美。

      匯編語言是難讀的,特別是對一些沒有匯編基礎的朋友,因此,本文將匯編翻譯成相應的C語言,以方便讀者分析問題。

      1. 代碼

         為了方便表述問題,本文選取只有虛函數(shù)的兩個類,當然,還有它的構(gòu)造函數(shù),如下:

      [cpp] view
      plaincopyprint?

      1. class Base      

      2. {     

      3.  public:     

      4.     virtual void f() { }     

      5.     virtual void g() { }     

      6. };     

      7. class Derive : public Base     

      8. {     

      9.   public:  

      10.     virtual void f() {}  

      11. };     

      12. int main()     

      13. {     

      14.   Derive d;     

      15.   Base *pb;  

      16.   pb = &d;   

      17.   pb->f();  

      18.   return 0;  

      19. }   

      2. 兩個類的虛函數(shù)表(vtable)

      使用g++ –Wall –S test.cpp命令,可以將上述的C++代碼生成它相應的匯編代碼。

      [cpp] view
      plaincopyprint?

      1. _ZTV4Base:  

      2.     .long   0    

      3.     .long   _ZTI4Base  

      4.     .long   _ZN4Base1fEv  

      5.     .long   _ZN4Base1gEv  

      6.     .weak   _ZTS6Derive  

      7.     .section    .rodata._ZTS6Derive,"aG",@progbits,_ZTS6Derive,comdat  

      8.     .type   _ZTS6Derive, @object  

      9.     .size   _ZTS6Derive, 8   

      _ZTV4Base是一個數(shù)據(jù)符號,它的命名規(guī)則是根據(jù)g++的內(nèi)部規(guī)則來命名的,如果你想查看它真正表示C++的符號名,可使用c++filt命令來轉(zhuǎn)換,例如:

      [lyt@t468 ~]$ c++filt _ZTV4Base 
      vtable for Base

      _ZTV4Base符號(或者變量)可看作為一個數(shù)組,它的第一項是0,第二項_ZIT4Base是關于Base的類型信息,這與typeid有關。為方便討論,我們略去此二項數(shù)據(jù)。 因此Base類的vtable的結(jié)構(gòu),翻譯成相應的C語言定義如下:

      [cpp] view
      plaincopyprint?

      1. unsigned long Base_vtable[] = {  

      2.     &Base::f(),  

      3.     &Base::g(),  

      4. };  

      而Derive的更是類似,只有稍為有點不同:

      [cpp] view
      plaincopyprint?

      1. _ZTV6Derive:  

      2.     .long   0    

      3.     .long   _ZTI6Derive  

      4.     .long   _ZN6Derive1fEv  

      5.     .long   _ZN4Base1gEv  

      6.     .weak   _ZTV4Base  

      7.     .section    .rodata._ZTV4Base,"aG",@progbits,_ZTV4Base,comdat  

      8.     .align 8  

      9.     .type   _ZTV4Base, @object  

      10.     .size   _ZTV4Base, 16   

      相應的C語言定義如下:

      [cpp] view
      plaincopyprint?

      1. unsigned long Derive_vtable[] = {  

      2.     &Derive::f(),  

      3.     &Base::g(),  

      4. };  

      從上面兩個類的vtable可以看到,Derive的vtable中的第一項重寫了Base類vtable的第一項。只要子類重寫了基類的虛函數(shù),那么子類vtable相應的項就會更改父類的vtable表項。 這一過程是編譯器自動處理的,并且每個的類的vtable內(nèi)容都放在數(shù)據(jù)段里面。

      3. 誰讓對象與vtable綁到一起

      上述代碼只是定義了每個類的vtable的內(nèi)容,但我們知道,帶有虛函數(shù)的對象在它內(nèi)部都有一個vtable指針,指向這個vtable,那么是何時指定的呢? 只要看看構(gòu)造函數(shù)的匯編代碼,就一目了然了:

      Base::Base()函數(shù)的編譯代碼如下:

      [cpp] view
      plaincopyprint?

      1. _ZN4BaseC1Ev:  

      2. .LFB6:  

      3.     .cfi_startproc  

      4.     .cfi_personality 0x0,__gxx_personality_v0  

      5.     pushl   %ebp  

      6.     .cfi_def_cfa_offset 8  

      7.     movl    %esp, %ebp  

      8.     .cfi_offset 5, -8  

      9.     .cfi_def_cfa_register 5  

      10.     movl    8(%ebp), %eax  

      11.     movl    $_ZTV4Base+8, (%eax)  

      12.     popl    %ebp  

      13.     ret  

      14.     .cfi_endproc   

      ZN4BaseC1Ev這個符號是C++函數(shù)Base::Base() 的內(nèi)部符號名,可使用c++flit將它還原。C++里的class,可以定義數(shù)據(jù)成員,函數(shù)成員兩種。但轉(zhuǎn)化到匯編層面時,每個對象里面真正存放的是數(shù)據(jù)成員,以及虛函數(shù)表。

      在上面的Base類中,由于沒有數(shù)據(jù)成員,因此它只有一個vtable指針。故Base類的定義,可以寫成如下相應的C代碼:

      [cpp] view
      plaincopyprint?

      1. struct Base {  

      2.     unsigned long **vtable;  

      3. }   

      構(gòu)造函數(shù)中最關鍵的兩句是:

          movl    8(%ebp), %eax 
          movl    $_ZTV4Base+8, (%eax)


      $_ZTV4Base+8 就是Base類的虛函數(shù)表的開始位置,因此,構(gòu)造函數(shù)對應的C代碼如下:

      [cpp] view
      plaincopyprint?

      1. void Base::Base(struct Base *this)  

      2. {  

      3.     this->vtable = &Base_vtable;  

      4. }  

      同樣地,Derive類的構(gòu)造函數(shù)如下:

      [cpp] view
      plaincopyprint?

      1. struct Derive {  

      2.     unsigned long **vtable;  

      3. };  

      4. void Derive::Derive(struct Derive *this)  

      5. {  

      6.     this->vtable = &Derive_vtable;  

      7. }  

      4. 實現(xiàn)運行時多態(tài)的最關鍵一步

      在造構(gòu)函數(shù)里面設置好的vtable的值,顯然,同一類型所有對象內(nèi)的vtable值都是一樣的,并且永遠不會改變。下面是main函數(shù)生成的匯編代碼,它展示了C++如何利用vtable來實現(xiàn)運行時多態(tài)。

      [cpp] view
      plaincopyprint?

      1. .globl main  

      2.     .type   main, @function  

      3. main:  

      4. .LFB3:  

      5.     .cfi_startproc  

      6.     .cfi_personality 0x0,__gxx_personality_v0  

      7.     pushl   %ebp  

      8.     .cfi_def_cfa_offset 8  

      9.     movl    %esp, %ebp  

      10.     .cfi_offset 5, -8  

      11.     .cfi_def_cfa_register 5  

      12.     andl    $-16, %esp  

      13.     subl    $32, %esp  

      14.     leal    24(%esp), %eax  

      15.     movl    %eax, (%esp)  

      16.     call    _ZN6DeriveC1Ev  

      17.     leal    24(%esp), %eax  

      18.     movl    %eax, 28(%esp)  

      19.     movl    28(%esp), %eax  

      20.     movl    (%eax), %eax  

      21.     movl    (%eax), %edx  

      22.     movl    28(%esp), %eax  

      23.     movl    %eax, (%esp)  

      24.     call    *%edx  

      25.     movl    $0, %eax  

      26.     leave  

      27.     ret   

      28.     .cfi_endproc  

          andl    $-16, %esp 
          subl    $32, %esp

          這兩句是為局部變量d和bp在堆棧上分配空間,也即如下的語句:

      Derive d;   
      Base *pb;

      leal    24(%esp), %eax 
      movl    %eax, (%esp) 
      call    _ZN6DeriveC1Ev

      esp+24是變量d的首地址,先將它壓到堆棧上,然后調(diào)用d的構(gòu)造函數(shù),相應翻譯成C語言則如下:

      Derive::Dervice(&d);

      leal    24(%esp), %eax 
      movl    %eax, 28(%esp)

      這里其實是將&d的值賦給pb,也即:

      pb = &d;

      最關鍵的代碼是下面這一段:

      [cpp] view
      plaincopyprint?

      1. movl    28(%esp), %eax  

      2. movl    (%eax), %eax  

      3. movl    (%eax), %edx  

      4. movl    28(%esp), %eax  

      5. movl    %eax, (%esp)  

      6. call    *%edx  

      翻譯成C語言也就傳神的那句:

      pb->vtable[0](bp);

      編譯器會記住f虛函數(shù)放在vtable的第0項,這是編譯時信息。

      5. 小結(jié)

      這里省略了很多關于編譯器和C++的細枝未節(jié),是出于討論方便用的需要。從上面的編譯代碼可以看到以下信息:

      1.每個類都有各有的vtable結(jié)構(gòu),編譯會正確填寫它們的虛函數(shù)表

      2. 對象在構(gòu)造函數(shù)時,設置vtable值為該類的虛函數(shù)表

      3.在指針或者引用時調(diào)用虛函數(shù),是通過object->vtable加上虛函數(shù)的offset來實現(xiàn)的。

      當然這僅僅是g++的實現(xiàn)方式,它和VC++的略有不同,但原理是一樣的。

      到此,相信大家對“c++中的虛函數(shù)”有了更深的了解,不妨來實際操作一番吧!這里是創(chuàng)新互聯(lián)網(wǎng)站,更多相關內(nèi)容可以進入相關頻道進行查詢,關注我們,繼續(xù)學習!


      當前名稱:c++中的虛函數(shù)
      當前路徑:http://www.ef60e0e.cn/article/pjjjjs.html
      99热在线精品一区二区三区_国产伦精品一区二区三区女破破_亚洲一区二区三区无码_精品国产欧美日韩另类一区
      1. <ul id="0c1fb"></ul>

        <noscript id="0c1fb"><video id="0c1fb"></video></noscript>
        <noscript id="0c1fb"><listing id="0c1fb"><thead id="0c1fb"></thead></listing></noscript>

        黑龙江省| 阜阳市| 阿鲁科尔沁旗| 黔江区| 河津市| 东丽区| 达州市| 乌兰察布市| 乌兰察布市| 淮北市| 修文县| 西吉县| 石景山区| 安庆市| 刚察县| 筠连县| 滁州市| 织金县| 镇宁| 云霄县| 武安市| 芦山县| 南木林县| 新建县| 乌兰浩特市| 屯昌县| 庄浪县| 广元市| 桃园市| 焦作市| 北流市| 苗栗县| 余姚市| 抚宁县| 集安市| 天峨县| 鄂州市| 石河子市| 犍为县| 土默特左旗| 南宁市|