程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> C++之旅 虛函數

C++之旅 虛函數

編輯:C++入門知識

C++之旅 虛函數


1、為什麼了解決什麼 多態指同一個實體同時具有多種形式。它是面向對象程序設計(OOP)的一個重要特征。如果一個語言只支持類而不支持多態,只能說明它是基於對象的,而不是面向對象的。C++中的多態性具體體現在運行和編譯兩個方面。運行時多態是動態多態,其具體引用的對象在運行時才能確定。編譯時多態是靜態多態,在編譯時就可以確定對象使用的形式。(靜態綁定和動態綁定) 多態:同一操作作用於不同的對象,可以有不同的解釋,產生不同的執行結果。在運行時,可以通過指向基類的指針,來調用實現派生類中的方法。 C++中,實現多態有以下方法:虛函數,抽象類,覆蓋,模板(重載和多態無關)。 多態就是允許方法重名 參數或返回值可以是父類型傳入或返回。允許將子類類型的指針賦值給父類類型的指針。
其實如果是這樣的目的話,函數指針也可以實現多態。或我們反過來虛函數就是通過類名查找其虛表指針*__vptr(void**)。

2、定義 簡單地說,那些被virtual關鍵字修飾的成員函數,就是虛函數。它的一般實現模型是:每一個類(class)有一個虛表(virtual table),內含該class之中有作用的虛(virtual)函數的地址,然後每個對象有一個vptr,指向虛表(virtual table)的所在。 這個類大小就會多4個字節,這4個字節就是VTABLE的地址,這個類裡的每個虛函數都是這個VTABLE數組的成員。
3、實現原理工作機制 我們只要有虛函數的類,編譯器都會為這個類創建一個VTABLE,用它來保存該類的所有虛函數地址。我們叫其函數指針數組。這個數組每個元素就是虛函數的地址。編譯器給VTABLE置入了一指針VPTR。VPTR就是VTABLE的入口地址。VPTR的值取決於對像內存的地址。 每個類其VTABLE是獨立唯一的,也就是說當構造該派生類實例(對象)時,那麼這個類會有一個virtual table,而每一個實例(對象)都會有一個virtual pointer(以下簡稱vptr)指向該類的virtual function tabl
4、例題:#include //www.realtoptv.com by zhangyj //======================================================== // 名字空間聲明 //======================================================== using std::cout; using std::endl; //Y = 0.30R + 0.59G + 0.11B , U = 0.493(B-Y), V = 0.877(R-Y) //R = Y + 1.4075 *(V - 128) //G = Y – 0.3455 *(U –128) – 0.7169 *(V –128) //B = Y + 1.779 *(U – 128) //======================================================== //======================================================== class RGB2YUV { public: //默認構造函數 RGB2YUV(int r = 1, int g = 1, int b = 1) : m_r(r), m_g(g), m_b(b) { cout << RGB2YUV constructor called << endl; } //定義為虛函數 virtual int Y() { return 0.30*m_r + 0.59*m_g + 0.11*m_b; } virtual int U() { return 0.493*( m_b - Y() ); } virtual int V() { return 0.877*(m_r - Y()); } //顯示 void ShowY() { cout << Y volume is << Y() << endl; } void ShowU() { cout << U volume is << U() << endl; } void ShowV() { cout << V volume is << V() << endl; } protected: int m_r; int m_g; int m_b; }; //======================================================== //======================================================== class PS_RGB2YUV : public RGB2YUV { public: PS_RGB2YUV(int r, int g, int b) :RGB2YUV(r, g, b){} //定義為虛函數 virtual int Y() { return 0.30*m_r + 0.59*m_g + 0.11*m_b+1; } virtual int U() { return 0.493*(m_b - Y())+1; } virtual int V() { return 0.877*(m_r - Y())+1; } }; //======================================================== //函數名 :main //函數說明 虛函數的實現機制 //函數參數 :無 //返回值 :0 //======================================================== int main() { RGB2YUV Wyuv(32, 32, 32); //基類對象定義 PS_RGB2YUV Wyuv_offset(32, 32, 32); //派生類對象定義 //顯示 Wyuv.ShowY(); Wyuv.ShowU(); Wyuv.ShowV(); //顯示派生類對象 Wyuv_offset.ShowY(); Wyuv_offset.ShowU(); Wyuv_offset.ShowV(); //顯示類的大小 cout << Wyuv's size is << sizeof(Wyuv) << endl; cout << Wyuv_offset's size is << sizeof(Wyuv_offset) << endl; system(pause); }  data-cke-saved-name= \
 
\
8、反匯編分析
//定義為虛函數 29: virtual int Y() 30: { 013C4AA0 55 push ebp 013C4AA1 8B EC mov ebp,esp 013C4AA3 81 EC CC 00 00 00 sub esp,0CCh 013C4AA9 53 push ebx 013C4AAA 56 push esi 013C4AAB 57 push edi 013C4AAC 51 push ecx 013C4AAD 8D BD 34 FF FF FF lea ediebp-0CCh] 013C4AB3 B9 33 00 00 00 mov ecx,33h 013C4AB8 B8 CC CC CC CC mov eax,0CCCCCCCCh 013C4ABD F3 AB rep stos dword ptr es:[edi] 013C4ABF 59 pop ecx 013C4AC0 89 4D F8 mov dword ptr [this],ecx //每個實例都有this,寄存器ECX裡面的值作為this指針地址 31: return 0.30*m_r + 0.59*m_g + 0.11*m_b; 013C4AC3 8B 45 F8 mov eax,dword ptr [this] 013C4AC6 F2 0F 2A 40 04 cvtsi2sd xmm0,dword ptr [eax+4] 013C4ACB F2 0F 59 05 60 DC 3C 01 mulsd xmm0,mmword ptr ds:[13CDC60h] 013C4AD3 8B 4D F8 mov ecx,dword ptr [this] 013C4AD6 F2 0F 2A 49 08 cvtsi2sd xmm1,dword ptr [ecx+8] 013C4ADB F2 0F 59 0D C8 DC 3C 01 mulsd xmm1,mmword ptr ds:[13CDCC8h] 013C4AE3 F2 0F 58 C1 addsd xmm0,xmm1 013C4AE7 8B 55 F8 mov edx,dword ptr [this] 013C4AEA F2 0F 2A 4A 0C cvtsi2sd xmm1,dword ptr [edx+0Ch] 013C4AEF F2 0F 59 0D B0 DB 3C 01 mulsd xmm1,mmword ptr ds:[13CDBB0h] 013C4AF7 F2 0F 58 C1 addsd xmm0,xmm1 013C4AFB F2 0F 2C C0 cvttsd2si eax,xmm0 32: }


virtual int Y()//調了2次值 74: { 013C4A30 55 push ebp 013C4A31 8B EC mov ebp,esp 013C4A33 81 EC CC 00 00 00 sub esp,0CCh 013C4A39 53 push ebx 013C4A3A 56 push esi 013C4A3B 57 push edi 013C4A3C 51 push ecx 013C4A3D 8D BD 34 FF FF FF lea edi,[ebp-0CCh] 013C4A43 B9 33 00 00 00 mov ecx,33h 013C4A48 B8 CC CC CC CC mov eax,0CCCCCCCCh 013C4A4D F3 AB rep stos dword ptr es:[edi] 013C4A4F 59 pop ecx 013C4A50 89 4D F8 mov dword ptr [this],ecx //每個實例都有this,寄存器ECX裡面的值作為this指針地址
75: return 0.30*m_r + 0.59*m_g + 0.11*m_b+1; 013C4A53 8B 45 F8 mov eax,dword ptr [this] //調其實例 013C4A56 F2 0F 2A 40 04 cvtsi2sd xmm0,dword ptr [eax+4] 013C4A5B F2 0F 59 05 60 DC 3C 01 mulsd xmm0,mmword ptr ds:[13CDC60h] 013C4A63 8B 4D F8 mov ecx,dword ptr [this] 013C4A66 F2 0F 2A 49 08 cvtsi2sd xmm1,dword ptr [ecx+8] 013C4A6B F2 0F 59 0D C8 DC 3C 01 mulsd xmm1,mmword ptr ds:[13CDCC8h] 013C4A73 F2 0F 58 C1 addsd xmm0,xmm1 75: return 0.30*m_r + 0.59*m_g + 0.11*m_b+1; 013C4A77 8B 55 F8 mov edx,dword ptr [this] //調其實例 013C4A7A F2 0F 2A 4A 0C cvtsi2sd xmm1,dword ptr [edx+0Ch] 013C4A7F F2 0F 59 0D B0 DB 3C 01 mulsd xmm1,mmword ptr ds:[13CDBB0h] 013C4A87 F2 0F 58 C1 addsd xmm0,xmm1 013C4A8B F2 0F 58 05 98 DD 3C 01 addsd xmm0,mmword ptr ds:[13CDD98h] 013C4A93 F2 0F 2C C0 cvttsd2si eax,xmm0 76: }
9、總結 A、dynamic(late ) binding和static(early) binding 的實現優缺點
B、內存布局的優缺點 C、多重繼承性的角度看優缺點 D、有多少種實現方法可以實現同樣的功能

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved