動態繫結的心得 (轉)

gugu99發表於2008-03-27
動態繫結的心得 (轉)[@more@]

  我前不久看了遍《thinking in C++》對動態繫結有了點心得,說出來與大家分享。

 如果一個基類(沒有父類)含有虛,那麼在編譯時,會生成一張虛擬函式表,表裡是該類中所有虛擬函式的地址(按出現順序排列);並且會在該類中動態的插入一個成員變數(__vfptr),它是一個指向這個虛擬函式表的指標。對於這個基類的所有子類,編譯器都會生成各自的虛擬函式表,並且把繼承得來的__vfptr指標指向它。例如 :namespace prefix = o ns = "urn:schemas--com::office" />

class BB{

public:

  BB();

  virtual ~BB();

  virtual void f1(){ cout << "BB"<< endl; };

};//BB的虛擬函式表中的一個函式是~BB(),第二個是f1();

class DD : public BB{

public:

  DD();

  virtual ~DD();  //表中的第一個函式

  virtual void f1(){ cout << "DD"<< endl; };//第二個

};

BB的虛擬函式表中的一個函式是~DD(),第二個是DD的f1();如果BB沒有定義f1()而定義了//virtual f2();則第二個函式是BB的f1(),第三個是f2();如果有以下的:

  DD dd;

  BB* pBB = &dd;

  pBB->f1();  //輸出的是"DD"

 

因為編譯器對pBB->f1() 不是直接CALL f1的地址,而是類似於:

mov  ecx,  d ptr [ebp-20h];//pBB變數的內容=類的首址=__vfptr的地址

mov  edx,  dword ptr [ecx];  //__vfptr的內容 = vtable的首地址

call dword ptr [edx+4]   //呼叫虛擬函式表的第二個函式:就是dd.f1()

例如class CC{

public:

  CC();

  virtual ~CC();

  virtual void f2(){cout << "CC" << endl;};

};

 

class DD: public BB, public CC{...}

 

有以下呼叫:

  DD dd;

  void* pCC = (CC*)&dd;  //關鍵在這一句!!!

  BB* pBB = (BB*)pCC;

  pBB->f1();  //竟然輸出是"cc",就是說呼叫的是CC::f2()!!!

  這是因為:dd內有兩個__vfptr(一個是BB的,一個是CC的)分別在在dd資料空間的前兩位,都指向DD的虛擬函式表。  其實在第二句pCC指向的是第二個__vfptr(CC的),根據上面的程式碼,可知編譯器對pBB->f1()的解釋就是呼叫"那個"虛擬函式表的第二個函式(因為f1()在BB的第二個),而"那個"虛擬函式表現在已經是CC的了。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10748419/viewspace-1001531/,如需轉載,請註明出處,否則將追究法律責任。

相關文章