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

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

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

常用鏈接

留言簿(1)

我參與的團隊

搜索

  •  

最新評論

閱讀排行榜

評論排行榜

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

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

推薦閱讀

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

先看這樣一段代碼

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();
}

 

結(jié)果是:

hello

hello

為何

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

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

于是我們把代碼改成這樣

 

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();
}

 

結(jié)果是:

hello
00401005
00401005
00401005
00401005
hello
Press any key to continue

 

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

調(diào)用的地址都是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個參數(shù)是線程函數(shù)的指針,為何這里報錯呢?

 

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

 

看看下面這篇文章關(guān)于這個問題的分析:

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

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

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


3。成員函數(shù)指針是強類型的。

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


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

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


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

 

 ”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。成員函數(shù)指針的轉(zhuǎn)化。本文所采用的代碼是想比較普通成員函數(shù)指針和虛函數(shù)指針在轉(zhuǎn)化的過程中存在那些差異:
對于符號”??_9@$B3AE“,我又找到了這樣的匯編代碼: 由此可以看出,對于虛函數(shù),即使是用過成員函數(shù)指針間接調(diào)用,仍然具有和直接調(diào)用一樣的特性。

 

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

 

; PVVBASEMEMFUNC      pVVBaseMemFunc   = &Base::foobar;
mov    DWORD PTR _pVVBaseMemFunc$[ebp], OFFSET FLAT:??_9@$B3AE ; `vcall'
取出符號”??_9@$B3AE“的值,存放于變量pVVBaseMemFunc所占內(nèi)存的前4個字節(jié)(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“代表的應該是一個存根函數(shù),這個函數(shù)首先根據(jù)this指針獲得虛函數(shù)表的指針,然后將指令再跳轉(zhuǎn)到相應的虛函數(shù)的地址。

 

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

 

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

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

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

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

    ; (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個字節(jié)。這12個字節(jié)中應該可以包含三個指針,其中的一個指針應該指向函數(shù)的地址,那另外兩個指針又指向那里呢?在《C++ Common Knowledge: Essential Intermediate Programming》(中文譯名:

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

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博客,轉(zhuǎn)載請標明出處:http://blog.csdn.net/eroswang/archive/2009/05/06/4153356.aspx

posted on 2011-04-27 17:14 沛沛 閱讀(407) 評論(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>
            亚洲美女精品一区| 黄色工厂这里只有精品| 亚洲视频 欧洲视频| 亚洲电影免费观看高清完整版在线| 亚洲免费中文| 国产日韩在线一区| 久久人人97超碰人人澡爱香蕉| 午夜亚洲视频| 激情久久综合| 欧美激情视频一区二区三区免费| 蜜桃久久精品一区二区| 99精品99| 在线视频亚洲欧美| 国模精品一区二区三区| 久久夜色精品国产欧美乱| 久久免费黄色| 中文国产亚洲喷潮| 午夜欧美大尺度福利影院在线看| 精品69视频一区二区三区| 欧美成人精品在线| 欧美日韩国产探花| 久久精品国产一区二区三区免费看| 久久精品在线观看| 一区二区三区高清在线 | 亚洲午夜在线观看视频在线| 一本色道久久综合狠狠躁的推荐| 国产精品高清网站| 久久亚洲电影| 欧美日韩精品欧美日韩精品 | 影音先锋久久精品| 亚洲精品视频啊美女在线直播| 国产精品午夜在线观看| 免费精品视频| 国产精品久久久久久久久久三级| 乱中年女人伦av一区二区| 欧美激情综合五月色丁香| 亚洲一区日本| 欧美成ee人免费视频| 性久久久久久久久久久久| 欧美成人精品在线观看| 欧美一区二区三区电影在线观看| 欧美顶级大胆免费视频| 久久国产欧美| 国产精品久久久久久福利一牛影视 | 国产精品视频大全| 亚洲黑丝一区二区| 国语自产精品视频在线看抢先版结局| 亚洲日本久久| 91久久极品少妇xxxxⅹ软件| 欧美在线一二三区| 欧美一级二区| 欧美午夜精品久久久久久浪潮 | 久久免费精品日本久久中文字幕| 欧美日韩卡一卡二| 91久久久国产精品| 亚洲黄色天堂| 久久久久久97三级| 久久久一区二区| 国产精品久久久久久久久免费桃花| 亚洲国产一区二区三区在线播| 极品少妇一区二区三区| 久久不射中文字幕| 久久青青草原一区二区| 国产午夜精品全部视频在线播放| 中日韩美女免费视频网址在线观看| 亚洲精品一区二区三区不| 久久久精品欧美丰满| 久久久久久久久久码影片| 国产精品一区2区| 亚洲一线二线三线久久久| 亚洲宅男天堂在线观看无病毒| 欧美日本一区二区视频在线观看| 亚洲激情二区| 日韩视频一区二区在线观看 | 久久久亚洲影院你懂的| 欧美ed2k| 亚洲三级免费电影| 欧美精品免费在线观看| 日韩视频一区二区在线观看| 中文无字幕一区二区三区| 欧美精选在线| 一本色道久久综合狠狠躁的推荐| 亚洲综合精品一区二区| 国产精品―色哟哟| 欧美一区精品| 欧美成年人视频| 亚洲老司机av| 国产精品国产a级| 午夜精品电影| 久久综合影视| 亚洲精品视频在线播放| 欧美日韩国产一级| 亚洲欧美激情视频在线观看一区二区三区| 欧美亚洲一级片| 在线成人激情视频| 欧美日本在线一区| 亚洲欧美日韩国产另类专区| 久久久久久久一区| 99xxxx成人网| 国产一区二区成人| 欧美成人性网| 亚洲一区欧美二区| 欧美大片免费看| 午夜久久一区| 亚洲经典在线| 国产精品日韩精品| 久热精品视频在线观看| 一区二区动漫| 美女视频黄 久久| 亚洲综合久久久久| 亚洲人成人一区二区三区| 国产精品成人午夜| 麻豆成人综合网| 亚洲综合日韩| 亚洲精品少妇30p| 老司机免费视频一区二区| 亚洲永久在线观看| 亚洲人成网站777色婷婷| 国产精品国内视频| 免费成人性网站| 久久av一区二区三区| 99视频+国产日韩欧美| 免费久久99精品国产自在现线| 亚洲综合色丁香婷婷六月图片| 亚洲人精品午夜| 国外成人网址| 国产日本欧美视频| 国产精品久久久久77777| 欧美激情性爽国产精品17p| 久久精品中文字幕免费mv| 亚洲一区三区视频在线观看 | 欧美亚洲免费电影| 一本色道久久综合狠狠躁篇怎么玩| 狠色狠色综合久久| 国产精品揄拍一区二区| 国产精品扒开腿做爽爽爽软件| 欧美精品在线观看播放| 欧美成人黑人xx视频免费观看| 久久经典综合| 欧美怡红院视频| 午夜国产一区| 欧美一区二区三区的| 亚洲欧美日韩一区在线观看| 亚洲一区三区电影在线观看| 亚洲视频专区在线| 亚洲一区二区三区免费视频| 99热精品在线观看| 在线一区免费观看| 亚洲天堂久久| 亚洲午夜久久久| 亚洲欧美日韩综合| 午夜精品久久久久久久99樱桃| 中文成人激情娱乐网| 亚洲永久免费观看| 欧美亚洲免费| 久久精品国产第一区二区三区| 久久精品国产清自在天天线| 久久都是精品| 久久综合激情| 欧美精品一区在线播放| 欧美亚洲不卡| 国产欧美一级| 亚洲第一色中文字幕| 亚洲日本激情| 亚洲天天影视| 久久久国产91| 欧美大片在线看| 99视频在线观看一区三区| 亚洲图片欧美一区| 久久国产精品久久久久久电车| 久久婷婷久久一区二区三区| 欧美1区2区3区| 国产精品乱码一区二三区小蝌蚪| 国产一区二区三区四区三区四| 在线日韩中文| 亚洲午夜精品一区二区| 久久精品成人| 亚洲精品网站在线播放gif| 亚洲一区久久久| 久久亚裔精品欧美| 欧美日韩小视频| 激情成人中文字幕| 亚洲一区二区精品| 巨乳诱惑日韩免费av| 最新国产の精品合集bt伙计| 亚洲综合日韩| 欧美大片在线观看| 国产日韩欧美一区二区| 亚洲人体1000| 久久精品日韩| 99国产精品| 久久深夜福利免费观看| 欧美午夜电影网| 亚洲欧洲在线免费| 久久精品国产久精国产思思| 亚洲人精品午夜在线观看| 久久激情视频久久| 欧美性大战久久久久久久蜜臀| 亚洲国产欧美一区二区三区久久| 亚洲欧美精品在线|