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

每天早晨叫醒你的不是鬧鐘,而是夢想

  C++博客 :: 首頁 :: 聯系 :: 聚合  :: 管理
  62 Posts :: 0 Stories :: 5 Comments :: 0 Trackbacks

常用鏈接

留言簿(1)

我參與的團隊

搜索

  •  

最新評論

閱讀排行榜

評論排行榜

From:http://blog.csdn.net/hairetz/archive/2009/05/06/4153252.aspx

個人感覺對于類的成員函數指針這塊講解的比較深入詳細

推薦閱讀

/////////////////////////////////////////////////

先看這樣一段代碼

class test
{
   public:
      test(int i){ m_i=i;}
      test(){}


      void hello()
      {
           printf("hello\n");
      }
   private:
       int m_i;
};

int main()
{
     test *p=new test();
     p->hello();
     p=NULL;
     p->hello();
}

 

結果是:

hello

hello

為何

p=NULL;
     p->hello();   這樣之后,NULL->hello()也依然有效呢?

我們第一反應一定是覺得類的實例的成員函數,不同于成員變量,成員函數全部都存在同一個地方,所以的類的實例來調用的時候,一定是調用相同的函數指針。(想想也是有道理的,成員函數都是一樣的功能,根本不需要實例化多個)

于是我們把代碼改成這樣

 

class test
{
    public:
        test(int i){ m_i=i;}
        test(){}


        void hello()
        {
            printf("hello\n");
        }


    private:
        int m_i;
};


typedef void (test::*HELLO_FUNC)();

int main()
{
     test *p=new test();
      test q;
      p->hello();
      HELLO_FUNC phello_fun=&test::hello;
      printf("%p\n",phello_fun);
      p=NULL;
      phello_fun=&test::hello;
      printf("%p\n",phello_fun);
      phello_fun=p->hello;
      printf("%p\n",phello_fun);
      phello_fun=q.hello;
      printf("%p\n",phello_fun);
      p->hello();
}

 

結果是:

hello
00401005
00401005
00401005
00401005
hello
Press any key to continue

 

也就是說不管是&test::hello,還是p->hello,或者q.hello,甚至于NULL->hello.

調用的地址都是0x00401005,也基本印證了我們的猜想。

 

事情到這里算是完了么?沒有。

有人問道這樣一段代碼:

SSVector& SSVector::assign2product4setup(const SVSet& A, const SSVector& x)
{
    int    ret_val= 

pthread_create(&pt,NULL,(void(*)(void*))SSVector::prefun,x);
}

void* SSVector::prefun (void* arg){
         const SSVector &tx =*((SSVector*) arg);
}
行報錯:invalid conversion from 'void (*)(void*)' to 'void* (*)(void*)'

pthread_create我就不解釋了,第3個參數是線程函數的指針,為何這里報錯呢?

 

說明普通的類成員函數的指針(如果它有函數指針的話),不同于一般的函數指針。

 

看看下面這篇文章關于這個問題的分析:

前言:在CSDN論壇經常會看到一些關于類成員函數指針的問題,起初我并不在意,以為成員函數指針和普通的函數指針是一樣的,沒有什么太多需要討論的。當我找來相關書籍查閱了一番以后,突然意識到我以前對成員函數指針的理解太過于幼稚和膚淺了,它即不像我以前認為的那樣簡單,它也不像我以前認為的那樣"默默無聞"。強烈的求知欲促使我對成員函數進行進一步的學習并有了這篇文章。

一。理論篇
在進行深入學習和分析之前,還是先看看書中是怎么介紹成員函數的。總結一下類成員函數指針的內容,應該包含以下幾個知識點:
1。成員函數指針并不是普通的函數指針。
2。編譯器提供了幾個新的操作符來支持成員函數指針操作:

1) 操作符"::*"用來聲明一個類成員函數指針,例如:
    typedef void (Base::*PVVBASEMEMFUNC)(void);        //Base is a class
2) 操作符"->*"用來通過對象指針調用類成員函數指針,例如:
    //pBase is a Base pointer and well initialized
    //pVIBaseMemFunc is a member function pointer and well initialized
    (pBase->*pVIBaseMemFunc)();
3) 操作符".*"用來通過對象調用類成員函數指針,例如:
    //baseObj is a Base object
    //pVIBaseMemFunc is a member function pointer and well initialized
    (baseObj.*pVIBaseMemFunc)();


3。成員函數指針是強類型的。

    typedef void (Base::*PVVBASEMEMFUNC)(void);
    typedef void (Derived::*PVVDERIVEMEMFUNC)(void);
PVVBASEMEMFUNC和PVVDERIVEMEMFUNC是兩個不同類型的成員函數指針類型。


4。由于成員函數指針并不是真真意義上的指針,所以成員函數指針的轉化就受限制。具體的轉化細節依賴于不同的編譯器,甚至是同一個編譯器的不同版本。不過,處于同一個繼承鏈中的不同類之間override的不同函數和虛函數還是可以轉化的。

    void* pVoid = reinterpret_cast<void*>(pVIBaseMemFunc);            //error
    int*  pInt  = reinterpret_cast<int*>(pVIBaseMemFunc);             //error
  pVIDeriveMemFunc = static_cast<PVIDERIVEMEMFUNC>(pVIBaseMemFunc);   //OK


二。實踐篇
有了上面的理論知識,我們對類成員函數指針有了大概的了解,但是我們對成員函數指針還存在太多的疑惑。既然說成員函數指針不是指針,那它到底是什么東東? 編譯器為什么要限制成員函數指針轉化?老辦法,我們還是分析匯編代碼揭示其中的秘密。首先,我寫了這樣兩個具有繼承關系的類:
接著,我又定義了一些成員函數指針類型:
最后,在main函數寫了一些測試代碼:
成功編譯后生成匯編代碼。老規矩,在分析匯編代碼的過程中還是只分析對解決問題有意義的匯編代碼,其他的就暫時忽略。
1。成員函數指針不是指針。從代碼看出,在main函數的調用棧(calling stack)中首先依次壓入四個成員函數指針,如果它們是普通指針的話,它們之間的偏移量應該是4個字節,可是實際的情況卻是這樣的:

 

 ”The implementation of the pointer to member function must store within itself information as to whether the member function to which it refers is virtual or nonvirtual, information about where to find the appropriate virtual function table pointer (see The Compiler Puts Stuff in Classes [11, 37]), an offset to be added to or subtracted from the function's this pointer (see Meaning of Pointer Comparison [28, 97]), and possibly other information. A pointer to member function is commonly implemented as a small structure that contains this information, although many other implementations are also in use. Dereferencing and calling a pointer to member function usually involves examining the stored information and conditionally executing the appropriate virtual or nonvirtual function calling sequence.“

2。成員函數指針的轉化。本文所采用的代碼是想比較普通成員函數指針和虛函數指針在轉化的過程中存在那些差異:
對于符號”??_9@$B3AE“,我又找到了這樣的匯編代碼: 由此可以看出,對于虛函數,即使是用過成員函數指針間接調用,仍然具有和直接調用一樣的特性。

 

    ; PVIBASEMEMFUNC pVIBaseMemFunc = &Base::setValue;
    mov    DWORD PTR _pVIBaseMemFunc$[ebp], OFFSET FLAT:?setValue@Base@@QAEXH@Z ;
    取出Base::setValue函數的地址,存放于變量pVIBaseMemFunc所占內存的前4個字節(DWORD)中。

 

; PVVBASEMEMFUNC      pVVBaseMemFunc   = &Base::foobar;
mov    DWORD PTR _pVVBaseMemFunc$[ebp], OFFSET FLAT:??_9@$B3AE ; `vcall'
取出符號”??_9@$B3AE“的值,存放于變量pVVBaseMemFunc所占內存的前4個字節(DWORD)中。

 

    _TEXT    SEGMENT
    ??_9@$B3AE PROC NEAR                    ; `vcall', COMDAT
    mov    eax, DWORD PTR [ecx]
    jmp    DWORD PTR [eax+4]
    ??_9@$B3AE ENDP                        ; `vcall'
    _TEXT    ENDS
符號”??_9@$B3AE“代表的應該是一個存根函數,這個函數首先根據this指針獲得虛函數表的指針,然后將指令再跳轉到相應的虛函數的地址。

 

    ; PVIDERIVEMEMFUNC pVIDeriveMemFunc = static_cast<PVIDERIVEMEMFUNC>(pVIBaseMemFunc);
    mov    eax, DWORD PTR _pVIBaseMemFunc$[ebp]
    mov    DWORD PTR _pVIDeriveMemFunc$[ebp], eax
直接將變量pVIBaseMemFunc所占內存的前4個字節(DWORD)的值付給了變量_pVIDeriveMemFunc所占內存的前4個字節中。

 

    ; PVVDERIVEMEMFUNC    pVVDeriveMemFunc = static_cast<PVVDERIVEMEMFUNC>(pVVBaseMemFunc);
    mov    eax, DWORD PTR _pVVBaseMemFunc$[ebp]
    mov    DWORD PTR _pVVDeriveMemFunc$[ebp], eax
直接將變量pVVBaseMemFunc所占內存的前4個字節(DWORD)的值付給了變量pVVDeriveMemFunc所占內存的前4個字節中。

由此可以看出,基類的成員函數指針轉化到相應的派生類的成員函數指針,值保持不變。當然這里的例子繼承關系相對來說比較簡單,如果存在多繼承和虛繼承的情況下,結果可能會復雜的多。

3。函數調用
下面的函數調用都大同小異,這里是列出其中的一個: 這里的匯編代碼并沒有給我們太多新鮮的內容:將對象的首地址(this指針)存放于寄存器ECX中,接著就將指令轉到變量_pVIBaseMemFunc所占內存的前4個字節所表示的地址。

到了這里,我們應該對成員函數指針有了進一步的了解。

    ; (baseObj.*pVIBaseMemFunc)(10);
    mov    esi, esp
    push    10                    ; 0000000aH
    lea    ecx, DWORD PTR _baseObj$[ebp]
    call    DWORD PTR _pVIBaseMemFunc$[ebp]
    cmp    esi, esp
    call    __RTC_CheckEsp  

 


由此可以看出,他們之間的偏移量是12個字節。這12個字節中應該可以包含三個指針,其中的一個指針應該指向函數的地址,那另外兩個指針又指向那里呢?在《C++ Common Knowledge: Essential Intermediate Programming》(中文譯名:

C++必知必會)這本書的第16章對這部分的內容做了說明,這個12個字節的偏移量正好印證了書中的內容:

class Base {
public:
    //ordinary member function
    void setValue(int iValue);

    //virtual member function
    virtual void dumpMe();
    virtual void foobar();

protected:
    int m_iValue;
};

class Derived:public Base{
public:
    //ordinary member function
    void setValue(int iValue);

    //virtual member function
    virtual void dumpMe();
    virtual void foobar();
private:
    double m_fValue;
};

 

    typedef void (Base::*PVVBASEMEMFUNC)(void);
    typedef void (Derived::*PVVDERIVEMEMFUNC)(void);
    typedef void (Base::*PVIBASEMEMFUNC)(int);
    typedef void (Derived::*PVIDERIVEMEMFUNC)(int);

 

int _tmain(int argc, _TCHAR* argv[])
{
    PVIBASEMEMFUNC pVIBaseMemFunc = &Base::setValue;
    PVIDERIVEMEMFUNC pVIDeriveMemFunc = static_cast<PVIDERIVEMEMFUNC>(pVIBaseMemFunc);

    PVVBASEMEMFUNC      pVVBaseMemFunc   = &Base::foobar;
    PVVDERIVEMEMFUNC    pVVDeriveMemFunc = static_cast<PVVDERIVEMEMFUNC>(pVVBaseMemFunc);

    Base baseObj;
    (baseObj.*pVIBaseMemFunc)(10);
    (baseObj.*pVVBaseMemFunc)();

    Derived deriveObj;
    (deriveObj.*pVIDeriveMemFunc)(20);
    (deriveObj.*pVVDeriveMemFunc)();

    return 0;
}

 

_deriveObj$ = -88
_baseObj$ = -60
_pVVDeriveMemFunc$ = -44
_pVVBaseMemFunc$ = -32
_pVIDeriveMemFunc$ = -20
_pVIBaseMemFunc$ = -8
_argc$ = 8
_argv$ = 12

 

本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/eroswang/archive/2009/05/06/4153356.aspx

posted on 2011-04-27 17:14 沛沛 閱讀(399) 評論(0)  編輯 收藏 引用 所屬分類: C++
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            久久精品亚洲一区二区| 国产欧美1区2区3区| 国产精品久久7| 欧美 日韩 国产精品免费观看| 欧美亚洲一级片| 亚洲一区二区三区久久| 日韩亚洲欧美高清| 欧美片网站免费| 欧美日韩一区成人| 国产精品地址| 国产亚洲精品aa| 在线观看成人av电影| 国产一区二区三区在线观看免费视频| 国产精品男人爽免费视频1| 亚洲——在线| 亚洲在线免费视频| 9人人澡人人爽人人精品| 日韩亚洲欧美精品| 亚洲免费影院| 久久综合中文| 欧美日韩一二三四五区| 国产日韩欧美一区在线| 在线精品国精品国产尤物884a| 亚洲第一精品久久忘忧草社区| 最新中文字幕一区二区三区| 亚洲视频第一页| 久久久久五月天| 亚洲精品久久在线| 午夜视黄欧洲亚洲| 亚洲欧美日韩系列| 欧美承认网站| 国内精品一区二区三区| 一区二区欧美在线观看| 另类国产ts人妖高潮视频| 99热免费精品在线观看| 久久精品在这里| 国产精品久久久亚洲一区| 亚洲福利视频网| 久久成人精品电影| 亚洲另类自拍| 免费观看不卡av| 国产日产欧产精品推荐色 | 国产精品视频不卡| 亚洲激情网站| 久久中文在线| 午夜视频一区| 国产精品入口麻豆原神| 99国产麻豆精品| 欧美不卡高清| 久久米奇亚洲| 黄色成人在线| 久久久精品一品道一区| 一区二区三区久久| 欧美日韩高清一区| 亚洲精品一区二区三区四区高清 | 国产精品男人爽免费视频1| 日韩视频一区二区三区| 欧美国产日韩在线| 欧美一区影院| 国产免费亚洲高清| 亚洲在线视频| 一区二区三区高清在线观看| 欧美精品aa| 亚洲精品在线视频观看| 麻豆成人在线播放| 久久美女艺术照精彩视频福利播放| 国产伦精品一区二区三区照片91| 久久久噜噜噜| 欧美在线在线| 国产亚洲精品一区二区| 国产乱理伦片在线观看夜一区| 中文一区在线| 亚洲图中文字幕| 国产拍揄自揄精品视频麻豆| 欧美在线不卡视频| 欧美呦呦网站| 美日韩精品视频| 亚洲激情午夜| 日韩视频在线一区二区三区| 欧美日韩精品一区| 午夜精品一区二区三区在线 | 欧美在线播放一区| 久久精品最新地址| 亚洲二区在线视频| 亚洲日本欧美| 国产精品va| 久久久久久**毛片大全| 久久久精品国产免大香伊| 最新国产乱人伦偷精品免费网站| 亚洲精品乱码久久久久久日本蜜臀| 欧美日韩三级电影在线| 久久国产福利| 欧美高清在线播放| 欧美一级精品大片| 免费成人av| 亚洲欧美韩国| 久热爱精品视频线路一| 国产精品99久久久久久人| 性色一区二区三区| 亚洲精品视频一区| 欧美高潮视频| 一区二区三区你懂的| 韩日在线一区| 日韩视频在线一区| 在线观看日韩av电影| 亚洲三级视频| 韩国v欧美v日本v亚洲v| 亚洲精品中文字幕在线观看| 国产一区二区欧美| 99re66热这里只有精品3直播| 国产亚洲美州欧州综合国| 欧美激情中文字幕乱码免费| 国产精品一区二区久久久久| 亚洲春色另类小说| 国产欧美日韩免费| 日韩午夜黄色| 亚洲激情女人| 亚洲国产精品成人一区二区| 国产日韩欧美在线观看| 日韩视频国产视频| 最新中文字幕亚洲| 久久午夜激情| 久久免费高清| 国产日韩欧美电影在线观看| 99re视频这里只有精品| 亚洲国产欧美日韩另类综合| 欧美尤物一区| 久久久久久夜精品精品免费| 国产精品久久久久aaaa樱花| 国产一区二区观看| 亚洲人成网站999久久久综合| 亚洲新中文字幕| 日韩午夜电影在线观看| 久久久久久久久久久成人| 性欧美暴力猛交另类hd| 欧美日韩国产综合视频在线观看| 免费中文字幕日韩欧美| 韩国av一区二区三区四区| 欧美成人有码| 亚洲国产日韩欧美在线动漫| 久久精品中文| 久热精品视频| 亚洲第一页在线| 久久综合一区二区| 亚洲成色www8888| 日韩一级精品视频在线观看| 欧美第一黄网免费网站| 亚洲国产精品美女| 99riav久久精品riav| 欧美精品一区二区视频| 99国产一区| 先锋亚洲精品| 国产一区视频网站| 性欧美大战久久久久久久免费观看| 欧美在线观看网址综合| 国产一区二区三区无遮挡| 久久精品一区二区| 亚洲福利小视频| 亚洲一区在线观看免费观看电影高清| 欧美日韩日日骚| 亚洲男人天堂2024| 另类激情亚洲| 亚洲美女黄网| 国产精品久久一区主播| 欧美一区二区三区喷汁尤物| 米奇777超碰欧美日韩亚洲| 亚洲精品美女在线观看播放| 欧美日韩黄视频| 欧美一区二区精美| 亚洲国产高清自拍| 亚洲欧美网站| 欧美—级高清免费播放| 亚洲一区二区在线免费观看| 久久久久欧美精品| 亚洲激情在线播放| 国产精品毛片a∨一区二区三区| 欧美在线观看一区二区| 欧美成人精品1314www| 亚洲一区二区三区色| 国内一区二区三区| 欧美视频在线观看免费网址| 久久精品国产69国产精品亚洲| 欧美激情区在线播放| 亚洲字幕在线观看| 亚洲国产精品成人精品| 国产精品日韩一区| 久久亚洲春色中文字幕| 在线一区亚洲| 激情小说另类小说亚洲欧美 | 亚洲精品极品| 久久精品国产亚洲一区二区| 日韩视频一区二区在线观看 | 久久野战av| 亚洲一级黄色片| 亚洲国产精品久久精品怡红院| 国产精品无人区| 欧美欧美天天天天操| 久久婷婷综合激情| 欧美亚洲综合网| 亚洲私人影吧|