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

C++分析研究  
C++
日歷
<2011年5月>
24252627282930
1234567
891011121314
15161718192021
22232425262728
2930311234
統(tǒng)計(jì)
  • 隨筆 - 92
  • 文章 - 4
  • 評(píng)論 - 4
  • 引用 - 0

導(dǎo)航

常用鏈接

留言簿

隨筆檔案

文章檔案

搜索

  •  

最新評(píng)論

閱讀排行榜

評(píng)論排行榜

 
  我曾經(jīng)自學(xué)過(guò)C++,現(xiàn)在回想起來(lái),當(dāng)時(shí)是什么都不懂。說(shuō)不上能使用C++,倒是被C++牽著鼻子走了。高中搞NOIP并不允許使用STL庫(kù),比賽中C++面向?qū)ο蟮臋C(jī)制基本沒(méi)有什么用武之地,所以高中搞NOIP名為用C++,其實(shí)就是c加上了cout和cin。
 
   前幾天看韓老師的《老碼識(shí)途》,里面記錄了一些C++面向?qū)ο髾C(jī)制的探索,又勾起了我的興趣。而這個(gè)學(xué)期自學(xué)了匯編,又給了我自己動(dòng)手探索提供了能力基礎(chǔ),自己上手以后,從一個(gè)更加底層的視角看C++機(jī)制的實(shí)現(xiàn),讓我在黑暗中摸到了馴服C++的韁繩。
 
   引用:
 
   本質(zhì)上是指針,這一點(diǎn)即使大家沒(méi)有看反匯編應(yīng)該也是猜到了。
 
   對(duì)象在內(nèi)存上的布局:
 
   1: class Father
 
   2: {
 
   3: int iA_;
 
   4: int iB_;
 
   5:
 
   6: void FuncA();
 
   7: void FuncB();
 
   8: };
 
   9:
 
   10: class Child : Father
 
   11: {
 
   12: int iC_;
 
   13: void FuncC();
 
   14: };
 
   一個(gè)Father對(duì)象里只包含 (低地址 –> 高地址) : iA_,iB_。也就是一個(gè)Father對(duì)象的大小是8個(gè)字節(jié),函數(shù)并不會(huì)占用內(nèi)存空間托福答案
 
   為什么不會(huì)?
 
   其實(shí)類的成員函數(shù)可以看做本質(zhì)上與普通函數(shù)相同。
 
   編譯器在編譯的時(shí)候就知道函數(shù)的位置,所以調(diào)用普通函數(shù)的時(shí)候會(huì)直接 call 函數(shù)地址(偏移)。也就是被硬編碼了,函數(shù)的地址是固定的( 不考慮重定位之類的情況 )。
 
   而成員函數(shù)的調(diào)用也是如此,只是編譯器還多做了一件事情,就是判斷這個(gè)對(duì)象有沒(méi)有調(diào)用這個(gè)函數(shù)的“權(quán)限”(函數(shù)不是你聲明的,當(dāng)然無(wú)權(quán)調(diào)用),“權(quán)限”不夠就會(huì)報(bào)錯(cuò),告訴那個(gè)對(duì)象類型沒(méi)有這個(gè)方法。
 
   所以,類對(duì)象的大小與這個(gè)類的方法數(shù)多少是沒(méi)關(guān)系的。成員函數(shù)和普通函數(shù)本質(zhì)上一樣,實(shí)現(xiàn)這個(gè)機(jī)制,要靠編譯器來(lái)做工作雅思答案
 
   this指針:
 
   成員函數(shù)與普通函數(shù)不同之處之一就是訪問(wèn)對(duì)象的數(shù)據(jù)。
 
   要訪問(wèn)一個(gè)對(duì)象的元素,說(shuō)白了就是要找到這個(gè)元素所在的內(nèi)存位置,也就是要有指針。
 
   我們沒(méi)有看到傳遞this指針,因?yàn)檫@件事又是編譯器幫我們做了。
 
   反匯編會(huì)看到對(duì)象調(diào)用一個(gè)方法的時(shí)候,會(huì)將這個(gè)對(duì)象的首部地址賦值給ecx寄存器,通過(guò)寄存器來(lái)傳遞this指針。
 
   我們?cè)诔蓡T函數(shù)里可以不需明寫this指針地調(diào)用對(duì)象元素,還是因?yàn)榫幾g器幫我們多做了一步“翻譯”。
 
   私有化:
 
   不多說(shuō),就是編譯器在編譯階段通過(guò)源碼來(lái)判斷某個(gè)元素是不是能夠被訪問(wèn),某個(gè)方法是不是能夠被調(diào)用,運(yùn)行的時(shí)候并不會(huì)有訪問(wèn)限制。看代碼:
 
   1: #include <stdio.h>
 
   2:
 
   3: class Exp
 
   4: {
 
   5: int iA_;
 
   6: int iB_;
 
   7:
 
   8: public:
 
   9: Exp()
 
   10: {
 
   11: iA_ = iB_ = 0;
 
   12: }
 
   13: void Out()
 
   14: {
 
   15: printf("%d \t %d \n",iA_,iB_);
 
   16: }
 
   17: };
 
   18:
 
   19: int main()
 
   20: {
 
   21: Exp oA;
 
   22: void *pC = &oA;
 
   23:
 
   24: oA.Out();
 
   25: *(int*)pC = 1;
 
   26: *(int*)((int)pC+4) = 2;
 
   27: oA.Out();
 
   28:
 
   29: return 0;
 
   30: }
 
   結(jié)果是: 0 0
 
   1 2
 
   雖然 iA_,iB_是私有的,但是還是被外界修改了。因?yàn)榫幾g器無(wú)法知道我干了這事(顯式的 oA.iA_ = 1 就被發(fā)現(xiàn)了哈)
 
   構(gòu)造與析構(gòu):
 
   說(shuō)道底還是編譯器幫我們?cè)诙嘧隽艘恍┕ぷ鳎闪艘恍╊~外代碼。
 
   需要注意的是:
 
   1: void Test( Father oP )
 
   2: {
 
   3: }
 
   4:
 
   5: int main()
 
   6: {
 
   7: Father oA;
 
   8: Test(oA);
 
   9: return 0;
 
   10: }
 
   會(huì)調(diào)用拷貝構(gòu)造函數(shù)。
 
   重載:
 
   一樣還是編譯器的功勞,C++最后生成的函數(shù)名是與參數(shù)有關(guān)的,所以又不同參數(shù)的函數(shù)最后生成的函數(shù)名不同,看似同名,實(shí)則不同。在函數(shù)調(diào)用的時(shí)候,編譯器會(huì)判斷參數(shù)的類型,相應(yīng)的可以生成一個(gè)函數(shù)名進(jìn)行“匹配”。( 當(dāng)然不止這么簡(jiǎn)單,還會(huì)考慮發(fā)生類型轉(zhuǎn)換的情況 )
 
   繼承:
 
   從內(nèi)存布局的角度上看
 
   1: struct Child : Father
 
   和
 
   1: struct Child
 
   2: {
 
   3: Father o;
 
   4: //other
 
   5: };
 
   相同(虛函數(shù)情況后面討論)。子類的前面部分和父類是一樣的。
 
   所以一個(gè)接受 Father * 參數(shù)的函數(shù)可以接受 Child *參數(shù),而且轉(zhuǎn)換是安全的北美托福答案
 
   有 Father & 類型參數(shù)的函數(shù)可以接受 Child &,但是繼承方式要public。But , why ?
 
   protected和private繼承模式,子類繼承的父類的接口對(duì)外都是隱藏的,所以以一個(gè)Father &傳入的參數(shù)所有的方法元素原則上是不可用的,用了肯定是違反規(guī)則的,編譯器判定這一點(diǎn),所以報(bào)錯(cuò)。
 
   虛函數(shù):
 
   比較特別的是這個(gè)。
 
   Question:為什么需要虛函數(shù)?
 
   網(wǎng)上看到的答案:基類可以通過(guò)虛函數(shù)對(duì)子類的相識(shí)功能進(jìn)行管理。(我的C++primer被借走以后就此失蹤,所以只能網(wǎng)上找了)。
 
   虛函數(shù)具體怎么回事就不細(xì)說(shuō)了,討論一下背后的機(jī)制。
 
   為了能夠?qū)崿F(xiàn)虛函數(shù),每個(gè)有虛函數(shù)的類有一張對(duì)應(yīng)的虛表。這個(gè)虛表儲(chǔ)存在只讀內(nèi)存區(qū),記錄了對(duì)應(yīng)函數(shù)的地址。(PS:一個(gè)類就只有一個(gè)虛表)
 
   每個(gè)類對(duì)象都要保存一個(gè)虛表指針,保存本類的虛表地址。所以你使用 Father *指針指向一個(gè)Child對(duì)象,調(diào)用的虛函數(shù)是Child的。
 
   虛表指針保存在每個(gè)對(duì)象的首部。
 
   1: class Child : Father
 
   2: {
 
   3: int iC_;
 
   4: void FuncC();
 
   5: virtual void VF();
 
   6: };
 
   現(xiàn)在這個(gè)Child對(duì)象較前面的多了四個(gè)字節(jié)。內(nèi)存布局(從低地址到高地址)是:虛表指針__vfptr,iA_,iB_,iC_。
 
   好。問(wèn)題來(lái)了,Child繼承了Father,但是Father的函數(shù)并沒(méi)有為Child再量身定做一次,也就是說(shuō)無(wú)論是Father對(duì)象還是Child對(duì)象,他們調(diào)用FuncA()都是同一個(gè)函數(shù)。但是Father并沒(méi)有__vfptr,Child對(duì)象在頭部多了這個(gè),F(xiàn)uncA()中用this指針定位iA_和iB_不是都不正確嗎?
 
   現(xiàn)象告訴我們FuncA()是可以正確訪問(wèn)iA_和iB_,所以推測(cè)Child對(duì)象在調(diào)用FuncA的時(shí)候,傳的不是真正的首部地址,而是往后偏移了四個(gè)字節(jié)托福改分
 
   反匯編,確實(shí)如此。這么說(shuō)Father類里不能調(diào)用虛函數(shù)了?當(dāng)然,F(xiàn)ather都還不知道虛函數(shù)這回事,怎么在FuncA中調(diào)用。
 
   還有一個(gè)有趣的現(xiàn)象:
 
   1: #include <stdio.h>
 
   2:
 
   3: class Base
 
   4: {
 
   5: public:
 
   6: virtual void ShowID()
 
   7: {
 
   8: printf("Base\n");
 
   9: }
 
   10: };
 
   11:
 
   12: class CB : public Base
 
   13: {
 
   14: public:
 
   15: virtual void ShowID()
 
   16: {
 
   17: printf("CB\n");
 
   18: }
 
   19: };
 
   20:
 
   21: class CC : public Base
 
   22: {
 
   23: public:
 
   24: virtual void ShowID()
 
   25: {
 
   26: printf("CC\n");
 
   27: }
 
   28: };
 
   29:
 
   30: void Test( CB& oB )
 
   31: {
 
   32: oB.ShowID();
 
   33: }
 
   34:
 
   35: int main()
 
   36: {
 
   37: Base oBase;
 
   38: CB oB;
 
   39: CC oC;
 
   40:
 
   41: CB* pCB = &oB;
 
   42:
 
   43: *(int*)(&oB) = *(int*)(&oC); //修改虛表指針
 
   44: oB.ShowID();
 
   45: ((CB*)(&oB))->ShowID();
 
   46: pCB->ShowID();
 
   47: Test(oB);
 
   48:
 
   49: return 0;
 
   50: }
 
   猜猜結(jié)果啊,買定離手。
 
   結(jié)果是:CB CB CC CC
 
   在43行的地方,修改了oB的虛表指針,讓其指向CC類的虛表。
 
   但是oB.ShowID()沒(méi)理會(huì)我們的修改,還是調(diào)用CB類的ShowID。反匯編,發(fā)現(xiàn)他沒(méi)走“獲取虛表指針,在虛表中得到相應(yīng)的函數(shù)地址”這一套,直接調(diào)用了。因?yàn)橐话闳瞬粫?huì)閑著蛋疼去改對(duì)象的虛表指針的,對(duì)象的類型是明確的,編譯器可以通過(guò)這些信息確定調(diào)用的函數(shù)地址,所以沒(méi)必要走他一套,這樣效率還更高托福答案
 
   而pCB->ShowID()就不同了,他很乖地地走了流程,因?yàn)橐粋€(gè)父類指針可以指向一個(gè)子類對(duì)象,編譯器無(wú)法找信息,所以走流程托福改分
 
   那現(xiàn)在糾結(jié)了,為神馬 ((CB*)(&oB))->ShowID() 輸出CB。
 
   反匯編看,發(fā)現(xiàn)編譯器又擅自做主,沒(méi)有走指針的流程。
 
   那你猜猜((Base*)(&oB))->ShowID();輸出的是什么?CC。
 
   比較二者的差異,可以大概發(fā)現(xiàn)一些端倪,什么時(shí)候走流程,什么時(shí)候不走。
 
   最后是Test(oB)了,前面說(shuō)過(guò)引用的本質(zhì)是指針,所以這個(gè)結(jié)果很好理解。
 
   還有,想過(guò)
 
   1: void Test2( Base oP )
 
   2: {
 
   3: oP.ShowID();
 
   4: }
 
   拷貝的時(shí)候有沒(méi)有拷貝虛表指針嗎?試試就知道,厄…發(fā)現(xiàn)沒(méi)有。
 
   前面說(shuō)過(guò)這樣會(huì)調(diào)用拷貝構(gòu)造函數(shù),但是你在這個(gè)函數(shù)你沒(méi)有寫虛表指針的賦值。但是邪惡的編譯器已經(jīng)幫你悄悄加上去了哈哈哈哈~。(唉?節(jié)操呢)
 
   RTTI
 
   每個(gè)類有特定的虛表地址,每個(gè)對(duì)象會(huì)保存這個(gè)虛表地址,應(yīng)該想到了吧,偷懶,不寫了。
 
   綜上。可以看到,面向?qū)ο髾C(jī)制在底層并不特別,機(jī)制的實(shí)現(xiàn)主要靠的是編譯器。
 
posted on 2013-04-16 11:42 HAOSOLA 閱讀(316) 評(píng)論(0)  編輯 收藏 引用

只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。
網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問(wèn)   Chat2DB   管理


 
Copyright © HAOSOLA Powered by: 博客園 模板提供:滬江博客
PK10開(kāi)獎(jiǎng) PK10開(kāi)獎(jiǎng)
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            欧美一区在线看| 久久久亚洲午夜电影| 欧美视频一区在线| 国产精品99久久99久久久二8 | 亚洲国产影院| 一卡二卡3卡四卡高清精品视频| 欧美日韩福利在线观看| 在线亚洲精品| 久久国产视频网| 永久555www成人免费| 欧美精品日韩一区| 亚洲在线不卡| 亚洲成人在线视频网站| 亚洲色在线视频| 国产香蕉久久精品综合网| 久久人人97超碰精品888 | 一区二区三区四区五区精品视频| 亚洲欧美日韩专区| 伊人一区二区三区久久精品| 女生裸体视频一区二区三区| 在线亚洲成人| 亚洲电影免费观看高清完整版| 亚洲一区在线观看免费观看电影高清 | 欧美精品激情在线| 翔田千里一区二区| 亚洲精品视频在线| 久久综合中文字幕| 亚洲永久免费视频| 亚洲国产精品一区二区www在线 | 欧美一区二区三区在| 亚洲成在线观看| 午夜综合激情| 99re66热这里只有精品4| 国产日产欧美精品| 欧美精品在线观看播放| 欧美制服丝袜| 在线视频日韩精品| 亚洲第一在线综合网站| 久久精品在线| 亚洲在线一区二区三区| 亚洲激情在线观看| 国产欧美日韩亚州综合| 欧美女主播在线| 久久久久久久久久看片| 亚洲男同1069视频| 日韩亚洲不卡在线| 亚洲国产欧美一区二区三区久久| 久久久久久久久一区二区| 亚洲一区不卡| 一区二区国产精品| 亚洲精品裸体| 亚洲高清激情| 一区在线免费观看| 国产亚洲在线| 国产一区二区日韩精品欧美精品 | 亚洲精品欧美日韩专区| 国产在线精品一区二区夜色| 欧美亚洲第一区| 欧美激情一区二区三区在线视频 | 欧美在线观看一区| 亚洲在线免费| 亚洲伊人一本大道中文字幕| 国产精品99久久久久久久vr| av成人动漫| 亚洲美女在线一区| 日韩午夜电影在线观看| 亚洲三级免费| 99热这里只有精品8| 亚洲精品小视频在线观看| 亚洲国产日韩欧美在线动漫| 影院欧美亚洲| 在线免费观看欧美| 亚洲第一黄色网| 亚洲经典在线| 99国产精品私拍| 国产精品99久久久久久久vr| 99综合在线| 亚洲一区网站| 欧美一区二区三区久久精品| 小嫩嫩精品导航| 久久国产99| 久久永久免费| 欧美韩日一区二区| 亚洲精品国产精品乱码不99按摩| 亚洲激情一区| 亚洲人成网站在线播| 亚洲久久一区二区| 亚洲嫩草精品久久| 久久久久国产精品www| 老司机精品久久| 欧美精品久久久久久久久久| 欧美精品在欧美一区二区少妇| 欧美日韩精品系列| 国产日产高清欧美一区二区三区| 国产小视频国产精品| 亚洲成人在线观看视频| 亚洲狼人精品一区二区三区| 亚洲一区二区网站| 久久精品一区蜜桃臀影院| 免费在线日韩av| 亚洲精品国产精品国产自| 亚洲专区一区| 久久综合99re88久久爱| 欧美激情一区二区三区四区| 欧美人与性禽动交情品| 国产精品永久免费视频| 亚洲国产精品成人| 中日韩高清电影网| 久久人人97超碰人人澡爱香蕉| 亚洲国产精品一区在线观看不卡 | 欧美久久影院| 国产一区二区日韩| 99精品国产在热久久下载| 性18欧美另类| 亚洲高清在线精品| 亚洲欧美在线播放| 欧美精品一线| 激情婷婷欧美| 亚洲一区免费观看| 亚洲成人在线免费| 精品成人一区二区| 亚洲一区观看| 欧美黄色小视频| 亚洲欧美在线另类| 欧美日本高清| 在线成人亚洲| 性欧美办公室18xxxxhd| 91久久午夜| 久久婷婷人人澡人人喊人人爽| 欧美日韩一区二| 亚洲国产精品va在线看黑人| 欧美中日韩免费视频| 日韩天堂在线观看| 免费欧美日韩国产三级电影| 国产女人18毛片水18精品| 亚洲美女视频| 欧美激情精品久久久| 欧美有码在线观看视频| 国产精品美女诱惑| 一道本一区二区| 亚洲国产精品久久久久| 久久精品国产亚洲aⅴ| 国产美女高潮久久白浆| 亚洲性感美女99在线| 亚洲欧洲一区二区三区在线观看 | 久久久久免费观看| 宅男精品导航| 欧美性jizz18性欧美| 亚洲精一区二区三区| 欧美激情网友自拍| 久久久噜噜噜久久久| 国产综合色产在线精品| 欧美一区二区三区在线视频| 亚洲一区二区三区在线播放| 国产精品久久波多野结衣| 一区二区成人精品 | 美女在线一区二区| 欧美综合77777色婷婷| 国产亚洲福利一区| 久久蜜桃香蕉精品一区二区三区| 午夜精品一区二区三区在线| 国产精品sm| 亚洲欧美日韩网| 亚洲一区二区三区在线播放| 欧美视频在线观看视频极品 | 免费不卡在线视频| 久久夜色精品国产欧美乱极品| 国内精品亚洲| 久久夜色精品国产亚洲aⅴ| 欧美主播一区二区三区| 尤物精品国产第一福利三区| 男同欧美伦乱| 牛人盗摄一区二区三区视频| 亚洲精品在线一区二区| 亚洲欧洲精品成人久久奇米网| 欧美日韩1区2区| 亚洲欧美中文日韩在线| 欧美一区二区视频在线| 伊人婷婷欧美激情| 亚洲激情成人在线| 国产精品久久九九| 久久久www成人免费精品| 久久野战av| 亚洲视频导航| 午夜视频久久久久久| 精品福利av| 亚洲日本在线观看| 国产欧美视频一区二区| 美女日韩欧美| 欧美裸体一区二区三区| 欧美亚洲色图校园春色| 久久精品成人一区二区三区蜜臀 | 一区二区亚洲精品国产| 亚洲黄色影院| 国产精品免费在线| 蜜臀av性久久久久蜜臀aⅴ| 欧美美女日韩| 久久精品一区二区三区中文字幕| 老鸭窝亚洲一区二区三区| 在线一区日本视频|