青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

chaosuper85

C++博客 首頁(yè) 新隨筆 聯(lián)系 聚合 管理
  118 Posts :: 0 Stories :: 3 Comments :: 0 Trackbacks

    C++虛函數(shù)探索筆記(1)——虛函數(shù)的簡(jiǎn)單示例分析

    關(guān)注問(wèn)題:

    虛函數(shù)的作用

    虛函數(shù)的實(shí)現(xiàn)原理

    虛函數(shù)表在對(duì)象布局里的位置

    虛函數(shù)的類的sizeof

    純虛函數(shù)的作用

    多級(jí)繼承時(shí)的虛函數(shù)表內(nèi)容

    虛函數(shù)如何執(zhí)行父類代碼

    多繼承時(shí)的虛函數(shù)表定位,以及對(duì)象布局

    虛析構(gòu)函數(shù)的作用

    虛函數(shù)在QT的信號(hào)與槽中的應(yīng)用

    虛函數(shù)與inline修飾符,static修飾符

    啰嗦兩句

    虛函數(shù)在C++里的作用是在是非常非常的大,很多講述C++的文章都會(huì)講到它

,要用好C++,就一定要學(xué)好虛函數(shù)。網(wǎng)絡(luò)上可以google到很多很多關(guān)于它的文章

,這一次的學(xué)習(xí),我不準(zhǔn)備去只是簡(jiǎn)單的閱讀了解那些文章,而是希望通過(guò)編寫

一些測(cè)試代碼,來(lái)對(duì)虛函數(shù)的一些實(shí)現(xiàn)機(jī)制,以及C++對(duì)象布局做一下探索。

    虛函數(shù)的簡(jiǎn)單示例 !

    虛函數(shù)常常出現(xiàn)在一些抽象接口類定義里,當(dāng)然,還有一個(gè)更常見(jiàn)的“特例

”,那就是虛析構(gòu)函數(shù),后面會(huì)提到這個(gè)。

    下面是一段關(guān)于虛函數(shù)的簡(jiǎn)單代碼,演示了使用基類接口操作對(duì)象時(shí)的效果


 //Source filename: Win32Con.cpp
#include <iostream>
using namespace std;
class parent1
{
public:
    virtual int fun1()=0;
};

class child1:public parent1
{
public:
    virtual int fun1()
    {
        cout<<"child1::fun1()"<<endl;
        return 0;
    }
};

class child2:public parent1
{
public:
    virtual int fun1()
    {
        cout<<"child2::fun1()"<<endl;
        return 0;
    }
};

void test_func1(parent1 *pp)
{
    pp->fun1();
}

int main(int argc, char* argv[])
{
    child1 co1;
    child2 co2;
    test_func1(&co1);
    test_func1(&co2);
    return 0;
}

 


    在上面的代碼里,類parent1是一個(gè)只具有純虛函數(shù)的接口類,這個(gè)類不能被

實(shí)例化,它唯一的用途就是抽象一些特定的接口函數(shù),當(dāng)然,在這里這個(gè)接口函

數(shù)就是純虛函數(shù) parent1::fun1()。

    而類child1和child2則是兩個(gè)從parent1繼承的類,我們要使用它定義具體的

類實(shí)例,所以它實(shí)現(xiàn)了由parent1繼承得來(lái)的fun1接口,并且各自的實(shí)現(xiàn)是不同的

    函數(shù) test_func1 的參數(shù)是一個(gè)parent1類型的指針,它所要完成的功能就是

調(diào)用這個(gè)parent1對(duì)象的fun1()函數(shù)。

    讓我們編譯運(yùn)行一下上面的代碼,可以看到下面的輸出

    child1::fun1()

    child2::fun1()

    很顯然,在兩次調(diào)用test_func1函數(shù)的時(shí)候,雖然傳入的參數(shù)都是一個(gè)

parent1的指針,但是卻都分別執(zhí)行了child1和child2各自的fun1函數(shù)!這就是

C++里類的多態(tài)。然而,這一切是怎么發(fā)生的呢?test_func1函數(shù)怎么會(huì)知道應(yīng)該

調(diào)用哪個(gè)函數(shù)的呢?我不準(zhǔn)備像其他人一樣畫若干圖來(lái)說(shuō)明,我準(zhǔn)備用具體某個(gè)

編譯器產(chǎn)生的對(duì)象布局以及相應(yīng)的匯編代碼來(lái)說(shuō)明這個(gè)過(guò)程(這個(gè)編譯器是

vs2008里的vc9)。

    我們先打開一個(gè)VS2008命令提示窗口,改變目錄到上面的代碼Win32Con.cpp

所在目錄,輸入下面的命令:

    cl  win32con.cpp  /d1reportSingleClassLayoutchild

    上面的命令可以編譯win32con.cpp源碼,同時(shí)生成里面類名包含child 的類

的對(duì)象布局(layout)

    注意:d1reportSingleClassLayout和后面的child是相連的!

    輸入上面的命令后看到的對(duì)象布局如下,紅色字為我添加的注釋
 class child1    size(4): 子類child1的對(duì)象布局,只包含一個(gè)vfptr,大小為

4字節(jié)
        +---
        | +--- (base class parent1) 這是被嵌套的父類parent1的對(duì)象布局
 0      | | {vfptr}
        | +---
        +---
這是child1的vfptr所指的虛函數(shù)表的布局,只包含一個(gè)函數(shù)的地址,就是child1

的fun1函數(shù)
child1::$vftable@:
        | &child1_meta
        |  0
 0      | &child1::fun1

child1::fun1 this adjustor: 0

class child2    size(4): 子類child2的對(duì)象布局,只包含一個(gè)vfptr,大小為4

字節(jié)
        +---
        | +--- (base class parent1) 這是被嵌套的父類parent1的對(duì)象布局
 0      | | {vfptr}
        | +---
        +---
這是child2的vfptr所指的虛函數(shù)表的布局,只包含一個(gè)函數(shù)的地址,就是child2

的fun1函數(shù)
child2::$vftable@:
        | &child2_meta
        |  0
 0      | &child2::fun1

child2::fun1 this adjustor: 0

 


    從上面的對(duì)象布局可以知道:

    每個(gè)子對(duì)象都有一個(gè)隱藏的成員變量vfptr(你當(dāng)然不能用這個(gè)名字訪問(wèn)到它

),它的值是指向該子對(duì)象的虛函數(shù)表,而虛函數(shù)表里填寫的函數(shù)地址是該子對(duì)

象的fun1函數(shù)地址。

    對(duì)一個(gè)包含有虛函數(shù)的類做sizeof操作的時(shí)候,除了能直接看到的成員變量,還得增加4字節(jié)(在32位機(jī)器上),就是vfptr這個(gè)指針的大小。

    所以當(dāng)test_func1進(jìn)行pp->fun1()調(diào)用的時(shí)候,會(huì)首先取出pp所指的內(nèi)存地址并按照parent1的內(nèi)存布局,獲取到vfptr指針(由于pp在兩次調(diào)用中分別指向co1和co2所以這里取得的實(shí)際上是co1的vfptr和co2的vfptr),然后從vfptr所指的虛函數(shù)表第一項(xiàng)(現(xiàn)在也只有 1 項(xiàng))取出作為將要調(diào)用的函數(shù),由于co1和co2在各自的虛函數(shù)表里填寫了各自的fun1的地址,于是pp->fun1()最終就調(diào)用到了co1和co2各自的fun1,輸出自然也就不同了。

    讓我們看看test_func1的反匯編代碼:
 void test_func1(parent1 *pp)
{
001C1530  push        ebp
001C1531  mov         ebp,esp
001C1533  sub         esp,0C0h
001C1539  push        ebx
001C153A  push        esi
001C153B  push        edi
001C153C  lea         edi,[ebp-0C0h]
001C1542  mov         ecx,30h
001C1547  mov         eax,0CCCCCCCCh
001C154C  rep stos    dword ptr es:[edi]
    pp->fun1();
001C154E  mov         eax,dword ptr [pp] //取得pp的值放到eax,即對(duì)象的地址
//取得對(duì)象的vfptr地址放到edx(因?yàn)関fptr在對(duì)象布局里拍在第一)
001C1551  mov         edx,dword ptr [eax]
001C1553  mov         esi,esp
001C1555  mov         ecx,dword ptr [pp]
001C1558  mov         eax,dword ptr [edx] //取出vfptr的第一個(gè)虛函數(shù)的地址到eax
001C155A  call        eax //調(diào)用虛函數(shù),即fun1()

    至此,應(yīng)該比較清楚虛函數(shù)機(jī)制的基本實(shí)現(xiàn)了。然而,也許你還會(huì)有這些問(wèn)題:

    虛函數(shù)表是每個(gè)子對(duì)象都有的么?

    虛函數(shù)是存在一個(gè)表里的,表的數(shù)據(jù)結(jié)構(gòu)是怎樣的,如何定位表里哪個(gè)才是我們要調(diào)用的虛函數(shù)?

    略作變化

    讓我們對(duì)前面的代碼做以下修改:

    定義一個(gè)普通類

    修改parent類,在fun1前增加虛函數(shù)fun2

    在child1里和child2里編寫fun2的具體實(shí)現(xiàn),一個(gè)在fun1之前編寫,另外一個(gè)在之后編寫修改后的編碼大致如下:

 class parent1
{
public:
    virtual int fun2()=0;
    virtual int fun1()=0;
};

class child
{
    int a;
};

class child1:public parent1
{
public:

    virtual int fun1()
    {
        cout<<"child1::fun1()"<<endl;
        return 0;
    }
    virtual int fun2()
    {
        cout<<"child1::fun2()"<<endl;
        return 0;
    }
};

    然后我們?cè)偈褂胏l命令以及/d1reportSingleClassLayout選項(xiàng)輸出相關(guān)的類對(duì)象布局情況:

 class child     size(4):  //在普通類child里,看不到vfptr的身影!
        +---
 0      | a
        +---

class child1    size(4):    //child1的對(duì)象布局,和之前沒(méi)有變化!
        +---
        | +--- (base class parent1)
 0      | | {vfptr}
        | +---
        +---
//child1的虛函數(shù)表多了fun2,并且兩個(gè)虛函數(shù)在表里的順序相同于在parent類里聲明的順序
child1::$vftable@:
        | &child1_meta
        |  0
 0      | &child1::fun2
 1      | &child1::fun1

child1::fun1 this adjustor: 0
child1::fun2 this adjustor: 0

    結(jié)論很明顯:

    虛函數(shù)表指針vfptr只在類里有虛擬函數(shù)的時(shí)候才會(huì)存在當(dāng)有多個(gè)虛函數(shù)的時(shí)候,虛函數(shù)在虛函數(shù)表里的順序由父類里虛函數(shù)的定義順序決定并且我們還可以觀察到:

    這個(gè)vfptr指針會(huì)放在類的起始處(這是必須的,vfptr在父類和子類的對(duì)象布局上必須一致!)

    虛函數(shù)表是以一個(gè)NULL指針標(biāo)識(shí)結(jié)束讓我們對(duì)這次簡(jiǎn)單的示例代碼測(cè)試來(lái)做個(gè)小小總結(jié):

    有虛函數(shù)的類,一定會(huì)有一個(gè)虛函數(shù)表指針vfptr這個(gè)vfptr指針會(huì)放在類的起始處虛函數(shù)表里會(huì)按基類聲明虛函數(shù)的順序在vfptr里存放函數(shù)地址虛函數(shù)表里存放的是函數(shù)地址是具體子類的實(shí)現(xiàn)函數(shù)的地址調(diào)用虛函數(shù)的時(shí)候,是從vfptr所指的函數(shù)表里獲取到函數(shù)地址,然后才調(diào)用具體的代碼。

 


posted on 2009-08-05 17:42 chaosuper 閱讀(351) 評(píng)論(1)  編輯 收藏 引用

Feedback

# re: C++中虛函數(shù)深度探索 一 (轉(zhuǎn)載)[未登錄](méi) 2009-08-06 23:15 ttylikl
呵呵,老兄,留個(gè)原文鏈接嘛!  回復(fù)  更多評(píng)論
  


只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。
網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問(wèn)   Chat2DB   管理


青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            一区二区三区在线观看视频| 国产一区在线免费观看| 久久天天躁狠狠躁夜夜爽蜜月| 国产欧美精品在线观看| 欧美午夜在线视频| 欧美日本韩国| 欧美三级黄美女| 欧美激情第8页| 欧美a级片网站| 欧美电影在线播放| 欧美久久久久免费| 国产精品久久久久91| 久久久久9999亚洲精品| 久久av老司机精品网站导航| 性xx色xx综合久久久xx| 久久久精品国产一区二区三区| 久久久国产精彩视频美女艺术照福利| 久久看片网站| 亚洲黄色av一区| 亚洲国产另类 国产精品国产免费| 亚洲激情视频在线播放| 亚洲午夜激情网页| 久久国内精品视频| 欧美日韩视频免费播放| 国产亚洲精品7777| 亚洲精品久久久一区二区三区| 亚洲人体1000| 久久―日本道色综合久久| 亚洲第一精品夜夜躁人人躁| 一本色道久久88精品综合| 久久精品国产亚洲一区二区| 欧美日韩不卡合集视频| 国产精品一国产精品k频道56| 好男人免费精品视频| 亚洲直播在线一区| 欧美韩国日本一区| 久久精品国产亚洲一区二区| 欧美午夜在线视频| 亚洲视频 欧洲视频| 欧美激情亚洲一区| 久久久噜噜噜久久| 伊人狠狠色j香婷婷综合| 亚洲综合首页| 91久久精品www人人做人人爽| 久久日韩粉嫩一区二区三区| 国产精品久久久久一区二区| 亚洲视频国产视频| 欧美日韩国产一区精品一区| 亚洲片国产一区一级在线观看| 欧美一级播放| 久久激情中文| 日韩视频免费在线观看| 亚洲人精品午夜| 欧美日产国产成人免费图片| 亚洲精品乱码久久久久久黑人 | 亚洲一区中文| 国产精品一区二区黑丝| 欧美在线视频观看| 久久阴道视频| 午夜视频在线观看一区二区| 亚洲欧美国产视频| 亚洲国产精品va在线看黑人| 亚洲三级视频| 影音先锋成人资源站| 亚洲精品久久| 黄网站色欧美视频| 亚洲精品免费一二三区| 欧美性开放视频| 久久青草久久| 国产精品久久久久婷婷| 麻豆成人在线| 国产欧美日韩免费| av成人免费观看| 日韩午夜激情| 午夜久久久久久| 欧美精品一卡| 久久久www成人免费无遮挡大片| 欧美视频中文在线看 | 欧美sm视频| 一区二区三区成人| 欧美国产日韩一区二区在线观看| 午夜精品久久久久久久99热浪潮 | 亚洲国产三级| 在线观看日韩欧美| 久久久九九九九| 欧美freesex交免费视频| 伊人春色精品| 欧美精品福利在线| 夜夜嗨一区二区三区| 亚洲在线国产日韩欧美| 国产精品免费网站| 欧美在线高清| 99视频国产精品免费观看| 亚洲欧美高清| 亚洲国产cao| 国产精品捆绑调教| 久久综合给合久久狠狠狠97色69| 欧美国产精品日韩| 亚洲视频欧美视频| 国产欧美日韩在线| 欧美精品18+| 亚洲一区二区高清| 亚洲精品久久7777| 午夜精品久久久久久久99热浪潮| 精品不卡一区二区三区| 欧美三级乱码| 蜜桃视频一区| 欧美制服丝袜| 久久久久久高潮国产精品视| 亚洲伦理在线免费看| 韩国精品一区二区三区| 欧美日韩无遮挡| 欧美紧缚bdsm在线视频| 久久久久久999| 亚洲网站在线播放| 亚洲国产精品成人| 国产在线精品二区| 国产精品在线看| 欧美日韩国产黄| 欧美激情国产精品| 另类av导航| 欧美精品123区| 欧美国产高清| 欧美精品在线视频| 欧美激情区在线播放| 欧美极品在线视频| 欧美日韩直播| 国内精品久久久久久影视8| 国产欧美一区二区三区久久人妖| 国产精品www网站| 国产精品欧美久久久久无广告| 国产精品扒开腿做爽爽爽视频| 国产精品久久一区主播| 一区二区视频免费完整版观看| 激情五月***国产精品| 亚洲国产精品美女| 亚洲午夜精品福利| 久久嫩草精品久久久久| 免费在线亚洲欧美| 99re视频这里只有精品| 久久精品国产999大香线蕉| 欧美精品国产一区二区| 国产乱码精品一区二区三区忘忧草| 国产日韩欧美精品综合| 亚洲国产精品尤物yw在线观看 | 国产精品成人一区二区艾草| 国产综合视频| 午夜精品一区二区三区电影天堂| 欧美激情一区二区久久久| 亚洲视频日本| 欧美男人的天堂| 在线观看亚洲精品视频| 久久视频一区| 欧美一区二区女人| 国产精品videosex极品| 欧美精品18videos性欧美| 激情亚洲网站| 欧美大片免费久久精品三p| 欧美一区二区黄| 在线欧美视频| 亚洲国产婷婷香蕉久久久久久99 | 欧美xxx成人| 日韩网站免费观看| 一二三区精品| 国产精品夜夜夜一区二区三区尤| 亚洲免费一在线| 亚洲制服av| 激情久久久久久| 91久久在线播放| 欧美三级精品| 久久综合国产精品台湾中文娱乐网| 久久精品毛片| 99精品热视频| 欧美激情亚洲自拍| 久久九九国产精品怡红院| 狠狠色丁香婷综合久久| 久久久久久伊人| 亚洲三级毛片| 国产欧美日本一区视频| 欧美国产成人精品| 国产精品福利片| 亚洲成色777777女色窝| 国产精品久久久久一区| 欧美激情网站在线观看| 国产欧美一区二区在线观看| 亚洲国产精品999| 国内揄拍国内精品少妇国语| 日韩午夜中文字幕| 亚洲黄色大片| 久久综合色综合88| 久久九九免费视频| 国产精品亚洲美女av网站| 亚洲精品视频啊美女在线直播| 一区二区视频免费在线观看| 久久国产一区| 免费成人网www| 亚洲第一页在线| 亚洲午夜久久久久久久久电影网| 老牛嫩草一区二区三区日本 | 在线成人免费观看|