亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > C++ > 正文

C++ 基礎教程:C++學習從零開始(四)

2020-05-23 14:25:11
字體:
來源:轉載
供稿:網友

虛函數

  虛繼承了一個函數類型的映射元素,按照虛繼承的說法,應該是間接獲得此函數的地址,但結果卻是間接獲得this參數的值。為了間接獲得函數的地址,C++又提出了一種語法--虛函數。在類型定義符“{}”中書寫函數聲明或定義時,在聲明或定義語句前加上關鍵字virtual即可,如下:

  struct A { long a; virtual void ABC(), BCD(); };

  void A::ABC() { a = 10; } void A::BCD() { a = 5; }

  上面等同于下面:

  struct A { void ( A::*pF )(); long a; void ABC(), BCD(); A(); };

  void A::ABC() { a = 10; } void A::BCD() { a = 5; }

  void ( A::*AVF[] )() = { A::ABC, A::BCD }; void A::A() { pF = AVF; }

  這里A的成員A::pF和之前的虛類表一樣,是一個指針,指向一個數組,這個數組被稱作虛函數表(Virtual Function Table),是一個函數指針的數組。這樣使用A::ABC時,將通過給出A::ABC在A::pF中的序號,由A::pF間接獲得,因此A a; a.ABC();將等同于( a.*( a.pF[0] ) )();。因此結構A的長度是8字節,再看下面的代碼:

  struct B : public A { long b; void ABC(); }; struct C : public A { long c; virtual void

  ABC(); };

  struct BB : public B { long bb; void ABC(); }; struct CC : public C { long cc; void

  ABC(); };

  void main() { BB bb; bb.ABC(); CC cc; cc.cc = 10; }

  首先,上面執行bb.ABC()但沒有給出BB::ABC或B::ABC的定義,因此上面雖然編譯通過,但連接時將失敗。其次,上面沒有執行cc.ABC();但連接時卻會說CC::ABC未定義以表示這里需要CC::ABC的地址,為什么?因為生成了CC的實例,而CC::pF就需要在編譯器自動為CC生成的缺省構造函數中被正確初始化,其需要CC::ABC的地址來填充。接著,給出如下的各函數定義。

  void B::ABC() { b = 13; } void C::ABC() { c = 13; }

  void BB::ABC() { bb = 13; b = 10; } void CC::ABC() { cc = 13; c = 10; }

  如上后,對于bb.ABC();,等同于bb.BB::ABC();,雖然有三個BB::ABC的映射元素,但只有一個映射元素的類型為void( BB:: )(),其映射BB::ABC的地址。由于BB::ABC并沒有用virtual修飾,因此上面將等同于bb.BB::ABC();而不是( bb.*( pF[0] ) )();,bb將為13。對于cc.ABC();也是同樣的,cc將為13。

  對于( ( B* )&bb )->ABC();,因為左側類型為B*,因此將為( ( B* )&bb )->B::ABC();,由于B::ABC并沒被定義成虛函數,因此這里等同于( ( B* )&bb )->B::ABC();,b將為13。對于( ( C* )&cc )->ABC();,同樣將為( ( C* )&cc )->C::ABC();,但C::ABC被修飾成虛函數,則前面等同于C *pC = &cc; ( pC->*( pC->pF[0] ) )();。這里先將cc轉換成C的實例,偏移0。然后根據pC->pF[0]來間接獲得函數的地址,為CC::ABC,c將為10。因為cc是CC的實例,在其被構造時將填充cc.pF。

  那么如下:

  void ( CC::*CCVF[] )() = { CC::ABC, CC::BCD }; CC::CC() { cc.pF = &CCVF; }

  因此導致pC->ABC();結果調用的竟是CC::ABC而不是C::ABC,這正是由于虛的緣故而間接獲得函數地址導致的。同樣道理,對于( ( A* )&cc )->ABC();和( ( A* )&bb )->ABC();都將分別調用CC::ABC和BB::ABC。但請注意,( pC->*( pC->pF[0] ) )();中,pC是C*類型的,而pC->pF[0]返回的CC::ABC是void( CC:: )()類型的,而上面那樣做將如何進行實例的隱式類型轉換?如果不進行將導致操作錯誤的成員??梢韵袂懊嫠f,讓CCVF的每個成員的長度為8個字節,另外4個字節記錄需要進行的偏移。但大多數類其實并不需要偏移(如上面的CC實例轉成A實例就偏移0),此法有些浪費資源。VC對此給出的方法如下,假設CC::ABC對應的地址為6000,并假設下面標號P處的地址就為6000,而CC::A_thunk對應的地址為5990。

  void CC::A_thunk( void *this )

  {

  this = ( ( char* )this ) + diff;

  P:

  // CC::ABC的正常代碼

  }

  因此pC->pF[0]的值為5990,而并不是CC::ABC對應的6000。上面的diff就是相應的偏

  移,對于上面的例子,diff應該為0,所以實際中pC->pF[0]的值還是6000(因為偏移為0,沒

  必要是5990)。此法被稱作thunk,表示完成簡單功能的短小代碼。對于多重繼承,如下:

  struct D : public A { long d; };

  struct E : public B, public C, public D { long e; void ABC() { e = 10; } };

  上面將有三個虛函數表,因為B、C和D都各自帶了一個虛函數表(因為從A派生)。

  結果上面等同于:

  struct E

  {

  void ( E::*B_pF )(); long B_a, b;

  void ( E::*C_pF )(); long C_a, c;

  void ( E::*D_pF )(); long D_a, d; long e; void ABC() { e = 10; } E();

  void E_C_thunk_ABC() { this = ( E* )( ( ( char* )this ) - 12 ); ABC(); }

  void E_D_thunk_ABC() { this = ( E* )( ( ( char* )this ) - 24 ); ABC(); }

  };

  void ( E::*E_BVF[] )() = { E::ABC, E::BCD };

  void ( E::*E_CVF[] )() = { E::E_C_thunk_ABC, E::BCD };

  void ( E::*E_DVF[] )() = { E::E_D_thunk_ABC, E::BCD };

  E::E() { B_pF = E_BVF; C_pF = E_CVF; D_pF = E_DVF; }

  結果E e; C *pC = &e; pC->ABC(); D *pD = &e; pD->ABC();,假設e的地址為3000,則pC的值為3012,pD的值為3024。結果pC->pF的值就是E_CVF,pD->pF的值就是E_DVF,如此就解決了偏移問題。同樣,對于前面的虛繼承,當類里有多個虛類表時,如:

  struct A {};

  struct B : virtual public A{}; struct C : virtual public A{}; struct D : virtual public A{};

  struct E : public B, public C, public D {};

  這是E將有三個虛類表,并且每個虛類表都將在E的缺省構造函數中被正確初始化以保證虛繼承的含義--間接獲得。而上面的虛函數表的初始化之所以那么復雜也都只是為了保證間接獲得的正確性。

  應注意上面將E_BVF的類型定義為void( E::*[] )()只是由于演示,希望在代碼上盡量符合語法而那樣寫,并不表示虛函數的類型只能是void( E:: )()。實際中的虛函數表只不過是一個數組,每個元素的大小都為4字節以記錄一個地址而已。因此也可如下:

  struct A { virtual void ABC(); virtual float ABC( double ); };

  struct B : public A { void ABC(); float ABC( double ); };

  則B b; A *pA = &b; pA->ABC();將調用類型為void( B:: )()的B::ABC,而pA->ABC( 34 );將調用類型為float( B:: )( double )的B::ABC。它們屬于重載函數,即使名字相同也都是兩個不同的虛函數。還應注意virtual和之前的public等,都只是從語法上提供給編譯器一些信息,它們給出的信息都是針對某些特殊情況的,而不是所有在使用數字的地方都適用,因此不能作為數字的類型。所以virtual不是類型修飾符,它修飾一個成員函數只是告訴編譯器在運用那個成員函數的地方都應該間接獲得其地址。

  為什么要提供虛這個概念?即虛函數和虛繼承的意義是什么?出于篇幅限制,將在本文的下篇給出它們意義的討論,即時說明多態性和實例復制等問題。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国产精品wwww| 国产精品丝袜白浆摸在线| 国产精品成人一区二区| 久久久欧美精品| 成人激情免费在线| 日本欧美一二三区| 久久影院资源网| 欧美电影免费在线观看| 91老司机在线| 777国产偷窥盗摄精品视频| 日本道色综合久久影院| 欧美床上激情在线观看| 成人在线视频福利| 国产精品高清在线观看| 中文字幕精品www乱入免费视频| 亚洲国产天堂网精品网站| 久热精品在线视频| 欧美日韩免费在线| 久久久久久久久综合| 国产丝袜精品视频| 色噜噜国产精品视频一区二区| 久久精视频免费在线久久完整在线看| 欧美多人爱爱视频网站| 国产欧美在线视频| 久热精品视频在线观看一区| 91精品视频在线播放| 久久激情视频久久| 欧美一级淫片videoshd| 国产一区私人高清影院| 精品视频在线导航| 精品一区二区三区四区| 欧美最猛黑人xxxx黑人猛叫黄| 日韩欧美综合在线视频| 欧美性猛交xxxx久久久| 国产91精品网站| 亚洲精品999| 国产偷亚洲偷欧美偷精品| 久久久999精品| 国产精品久久久久久婷婷天堂| 国产精品精品视频一区二区三区| 欧美高清在线视频观看不卡| 九九热视频这里只有精品| 波霸ol色综合久久| 国产91精品久久久| 国产亚洲欧洲高清一区| 亚洲www永久成人夜色| 在线播放国产一区中文字幕剧情欧美| 综合136福利视频在线| 狠狠色狠狠色综合日日五| 最新国产成人av网站网址麻豆| 亚洲xxx自由成熟| 成人有码在线视频| 国产精品pans私拍| 国产精品尤物福利片在线观看| 国产精品美女视频网站| 国产日韩av在线播放| 好吊成人免视频| 久久久久久午夜| 97香蕉超级碰碰久久免费的优势| 国产91精品网站| 91国内产香蕉| 国产丝袜高跟一区| 欧美色图在线视频| 久久久综合av| 日韩av在线影视| 日韩欧美国产一区二区| 成人黄色免费片| 国产精品99免视看9| 国产成人av在线播放| 国产一区视频在线| 国产精选久久久久久| 青青a在线精品免费观看| 日韩小视频在线观看| 久久成人18免费网站| 欧美日韩在线视频一区| 77777亚洲午夜久久多人| 亚洲欧洲午夜一线一品| 国产精品香蕉国产| 欧美乱妇高清无乱码| 国产一区二区激情| 亚洲成人激情小说| 亚洲成人av片在线观看| 91国产精品91| 97热在线精品视频在线观看| 亚洲国产精品免费| 欧美性猛交xxxx富婆弯腰| 久久久黄色av| 久久精品国产一区| 亚洲欧洲偷拍精品| 97欧美精品一区二区三区| 91精品国产91久久久久福利| 91牛牛免费视频| 欧美高清在线播放| 久久久久日韩精品久久久男男| 一区二区亚洲欧洲国产日韩| 亚洲欧美日本精品| 国产精品久久不能| 精品亚洲aⅴ在线观看| 2018日韩中文字幕| 美女黄色丝袜一区| 亚洲欧美精品中文字幕在线| 欧美日韩国产精品一区二区不卡中文| 欧美极品美女视频网站在线观看免费| 国产丝袜精品第一页| 国产啪精品视频网站| 一区二区av在线| 5566日本婷婷色中文字幕97| 另类图片亚洲另类| 国产精品第二页| 不卡中文字幕av| 91精品国产色综合久久不卡98口| 97在线免费视频| 国产一区香蕉久久| 日韩美女视频在线观看| 91麻豆桃色免费看| 国产精品自拍小视频| 97精品国产aⅴ7777| 国产精品扒开腿做爽爽爽男男| 国产精品久久久久久久久久尿| 亚洲男人的天堂在线| 欧美成人网在线| 日韩欧美一区视频| 国产精品视频播放| 久久久在线免费观看| 成人亚洲综合色就1024| 欧美激情免费视频| 久久久久久亚洲精品| 91av在线网站| 国产精品欧美一区二区| 亚洲人成电影在线观看天堂色| 国产女同一区二区| 最近中文字幕mv在线一区二区三区四区| 日本中文字幕不卡免费| 777777777亚洲妇女| 岛国av在线不卡| 国产精品一区二区三区毛片淫片| 久久99精品久久久久久琪琪| 国产91精品久久久| 欧美人交a欧美精品| 日本高清久久天堂| 亚洲第一天堂无码专区| 国内精品美女av在线播放| 中文字幕日韩综合av| 欧美—级高清免费播放| 国内精品久久影院| 亚洲黄色av网站| 9.1国产丝袜在线观看| 国产不卡av在线| 久久精品国产亚洲7777| 九九久久国产精品| 九色精品美女在线| 欧美影院在线播放| 午夜免费久久久久| 亚洲aⅴ日韩av电影在线观看| 九九热精品视频国产| 欧美在线免费视频| 成人黄色中文字幕| 91免费在线视频网站| 九九热精品视频| 18久久久久久| 久久夜色精品国产亚洲aⅴ| 日韩欧美亚洲成人| 91精品国产91久久久久久吃药| 国产精品偷伦一区二区|