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

C++分析研究  
C++
日歷
<2013年4月>
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011
統計
  • 隨筆 - 92
  • 文章 - 4
  • 評論 - 4
  • 引用 - 0

導航

常用鏈接

留言簿

隨筆檔案

文章檔案

搜索

  •  

最新評論

閱讀排行榜

評論排行榜

 
  我曾經自學過C++,現在回想起來,當時是什么都不懂。說不上能使用C++,倒是被C++牽著鼻子走了。高中搞NOIP并不允許使用STL庫,比賽中C++面向對象的機制基本沒有什么用武之地,所以高中搞NOIP名為用C++,其實就是c加上了cout和cin。
 
   前幾天看韓老師的《老碼識途》,里面記錄了一些C++面向對象機制的探索,又勾起了我的興趣。而這個學期自學了匯編,又給了我自己動手探索提供了能力基礎,自己上手以后,從一個更加底層的視角看C++機制的實現,讓我在黑暗中摸到了馴服C++的韁繩。
 
   引用:
 
   本質上是指針,這一點即使大家沒有看反匯編應該也是猜到了。
 
   對象在內存上的布局:
 
   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: };
 
   一個Father對象里只包含 (低地址 –> 高地址) : iA_,iB_。也就是一個Father對象的大小是8個字節,函數并不會占用內存空間托福答案
 
   為什么不會?
 
   其實類的成員函數可以看做本質上與普通函數相同。
 
   編譯器在編譯的時候就知道函數的位置,所以調用普通函數的時候會直接 call 函數地址(偏移)。也就是被硬編碼了,函數的地址是固定的( 不考慮重定位之類的情況 )。
 
   而成員函數的調用也是如此,只是編譯器還多做了一件事情,就是判斷這個對象有沒有調用這個函數的“權限”(函數不是你聲明的,當然無權調用),“權限”不夠就會報錯,告訴那個對象類型沒有這個方法。
 
   所以,類對象的大小與這個類的方法數多少是沒關系的。成員函數和普通函數本質上一樣,實現這個機制,要靠編譯器來做工作雅思答案
 
   this指針:
 
   成員函數與普通函數不同之處之一就是訪問對象的數據。
 
   要訪問一個對象的元素,說白了就是要找到這個元素所在的內存位置,也就是要有指針。
 
   我們沒有看到傳遞this指針,因為這件事又是編譯器幫我們做了。
 
   反匯編會看到對象調用一個方法的時候,會將這個對象的首部地址賦值給ecx寄存器,通過寄存器來傳遞this指針。
 
   我們在成員函數里可以不需明寫this指針地調用對象元素,還是因為編譯器幫我們多做了一步“翻譯”。
 
   私有化:
 
   不多說,就是編譯器在編譯階段通過源碼來判斷某個元素是不是能夠被訪問,某個方法是不是能夠被調用,運行的時候并不會有訪問限制。看代碼:
 
   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: }
 
   結果是: 0 0
 
   1 2
 
   雖然 iA_,iB_是私有的,但是還是被外界修改了。因為編譯器無法知道我干了這事(顯式的 oA.iA_ = 1 就被發現了哈)
 
   構造與析構:
 
   說道底還是編譯器幫我們在多做了一些工作,生成了一些額外代碼。
 
   需要注意的是:
 
   1: void Test( Father oP )
 
   2: {
 
   3: }
 
   4:
 
   5: int main()
 
   6: {
 
   7: Father oA;
 
   8: Test(oA);
 
   9: return 0;
 
   10: }
 
   會調用拷貝構造函數。
 
   重載:
 
   一樣還是編譯器的功勞,C++最后生成的函數名是與參數有關的,所以又不同參數的函數最后生成的函數名不同,看似同名,實則不同。在函數調用的時候,編譯器會判斷參數的類型,相應的可以生成一個函數名進行“匹配”。( 當然不止這么簡單,還會考慮發生類型轉換的情況 )
 
   繼承:
 
   從內存布局的角度上看
 
   1: struct Child : Father
 
   和
 
   1: struct Child
 
   2: {
 
   3: Father o;
 
   4: //other
 
   5: };
 
   相同(虛函數情況后面討論)。子類的前面部分和父類是一樣的。
 
   所以一個接受 Father * 參數的函數可以接受 Child *參數,而且轉換是安全的北美托福答案
 
   有 Father & 類型參數的函數可以接受 Child &,但是繼承方式要public。But , why ?
 
   protected和private繼承模式,子類繼承的父類的接口對外都是隱藏的,所以以一個Father &傳入的參數所有的方法元素原則上是不可用的,用了肯定是違反規則的,編譯器判定這一點,所以報錯。
 
   虛函數:
 
   比較特別的是這個。
 
   Question:為什么需要虛函數?
 
   網上看到的答案:基類可以通過虛函數對子類的相識功能進行管理。(我的C++primer被借走以后就此失蹤,所以只能網上找了)。
 
   虛函數具體怎么回事就不細說了,討論一下背后的機制。
 
   為了能夠實現虛函數,每個有虛函數的類有一張對應的虛表。這個虛表儲存在只讀內存區,記錄了對應函數的地址。(PS:一個類就只有一個虛表)
 
   每個類對象都要保存一個虛表指針,保存本類的虛表地址。所以你使用 Father *指針指向一個Child對象,調用的虛函數是Child的。
 
   虛表指針保存在每個對象的首部。
 
   1: class Child : Father
 
   2: {
 
   3: int iC_;
 
   4: void FuncC();
 
   5: virtual void VF();
 
   6: };
 
   現在這個Child對象較前面的多了四個字節。內存布局(從低地址到高地址)是:虛表指針__vfptr,iA_,iB_,iC_。
 
   好。問題來了,Child繼承了Father,但是Father的函數并沒有為Child再量身定做一次,也就是說無論是Father對象還是Child對象,他們調用FuncA()都是同一個函數。但是Father并沒有__vfptr,Child對象在頭部多了這個,FuncA()中用this指針定位iA_和iB_不是都不正確嗎?
 
   現象告訴我們FuncA()是可以正確訪問iA_和iB_,所以推測Child對象在調用FuncA的時候,傳的不是真正的首部地址,而是往后偏移了四個字節托福改分
 
   反匯編,確實如此。這么說Father類里不能調用虛函數了?當然,Father都還不知道虛函數這回事,怎么在FuncA中調用。
 
   還有一個有趣的現象:
 
   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: }
 
   猜猜結果啊,買定離手。
 
   結果是:CB CB CC CC
 
   在43行的地方,修改了oB的虛表指針,讓其指向CC類的虛表。
 
   但是oB.ShowID()沒理會我們的修改,還是調用CB類的ShowID。反匯編,發現他沒走“獲取虛表指針,在虛表中得到相應的函數地址”這一套,直接調用了。因為一般人不會閑著蛋疼去改對象的虛表指針的,對象的類型是明確的,編譯器可以通過這些信息確定調用的函數地址,所以沒必要走他一套,這樣效率還更高托福答案
 
   而pCB->ShowID()就不同了,他很乖地地走了流程,因為一個父類指針可以指向一個子類對象,編譯器無法找信息,所以走流程托福改分
 
   那現在糾結了,為神馬 ((CB*)(&oB))->ShowID() 輸出CB。
 
   反匯編看,發現編譯器又擅自做主,沒有走指針的流程。
 
   那你猜猜((Base*)(&oB))->ShowID();輸出的是什么?CC。
 
   比較二者的差異,可以大概發現一些端倪,什么時候走流程,什么時候不走。
 
   最后是Test(oB)了,前面說過引用的本質是指針,所以這個結果很好理解。
 
   還有,想過
 
   1: void Test2( Base oP )
 
   2: {
 
   3: oP.ShowID();
 
   4: }
 
   拷貝的時候有沒有拷貝虛表指針嗎?試試就知道,厄…發現沒有。
 
   前面說過這樣會調用拷貝構造函數,但是你在這個函數你沒有寫虛表指針的賦值。但是邪惡的編譯器已經幫你悄悄加上去了哈哈哈哈~。(唉?節操呢)
 
   RTTI
 
   每個類有特定的虛表地址,每個對象會保存這個虛表地址,應該想到了吧,偷懶,不寫了。
 
   綜上。可以看到,面向對象機制在底層并不特別,機制的實現主要靠的是編譯器。
 
posted on 2013-04-16 11:42 HAOSOLA 閱讀(314) 評論(0)  編輯 收藏 引用
 
Copyright © HAOSOLA Powered by: 博客園 模板提供:滬江博客
PK10開獎 PK10開獎
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            国产精品v日韩精品| 亚洲欧美精品一区| 亚洲视频第一页| 亚洲精品网站在线播放gif| 在线国产精品播放| 亚洲国产精品电影在线观看| 亚洲欧洲综合| 亚洲一区二区在线视频| 欧美在线影院在线视频| 久久综合久色欧美综合狠狠 | 国产午夜精品全部视频在线播放| 久久久精品五月天| 麻豆久久精品| 一本色道久久综合亚洲精品不卡| 亚洲尤物在线| 久久精品国产一区二区三区| 久久精品人人| 亚洲国产精品久久久| 一本色道久久综合亚洲精品小说| 欧美在线一级视频| 欧美刺激性大交免费视频| 91久久久精品| 欧美在线999| 欧美日韩中文字幕在线视频| 国产一区二区精品久久91| 亚洲精品国久久99热| 久久精品国产99| 亚洲剧情一区二区| 蜜桃久久av一区| 国产区在线观看成人精品| 亚洲美女精品成人在线视频| 亚洲欧美日韩网| 亚洲综合色丁香婷婷六月图片| 激情六月婷婷综合| 亚洲美女色禁图| 久久九九精品| 99精品国产在热久久| 久久综合狠狠| 欧美日韩成人综合在线一区二区| 一区二区三欧美| 午夜精品免费视频| 欧美日韩精品系列| 亚洲精品色图| 美女黄网久久| 欧美亚洲在线视频| 国产精品成人aaaaa网站| 91久久夜色精品国产九色| 久久精品二区三区| 亚洲制服丝袜在线| 国产精品福利在线观看网址| 99视频有精品| 亚洲区第一页| 欧美国产日产韩国视频| 亚洲福利视频网| 男女精品网站| 久久综合国产精品| 在线观看视频一区| 免费成人av| 久久全球大尺度高清视频| 精品999网站| 免费成人黄色av| 久久久久久自在自线| 一区二区三区在线看| 久久亚洲欧美国产精品乐播| 久久大逼视频| 在线国产亚洲欧美| 欧美黄色aaaa| 国产精品人成在线观看免费| 亚洲国产成人精品女人久久久 | 亚洲精品自在久久| 欧美国产日本在线| 欧美日产一区二区三区在线观看| 欧美激情一区二区三区在线 | 亚洲精品日韩在线| 欧美激情精品久久久久久免费印度| 欧美国产欧美综合| av成人手机在线| 亚洲最快最全在线视频| 国产精品久久二区| 欧美在线免费播放| 久久精视频免费在线久久完整在线看 | 亚洲高清一二三区| 欧美国产精品| 国产精品99免费看 | 国产主播精品| 久久躁日日躁aaaaxxxx| 久久夜色精品国产| 亚洲免费成人| 午夜精品国产| 亚洲激情一区二区三区| 一区二区三区日韩精品| 激情亚洲网站| 一本大道久久a久久综合婷婷| 久久免费观看视频| 夜夜嗨av一区二区三区中文字幕| 午夜在线一区二区| 久久看片网站| 亚洲欧美日韩在线观看a三区| 亚洲电影有码| 国产精品一二三四| 亚洲韩日在线| 国产日韩精品久久久| 亚洲精品1区2区| 黄色精品网站| 亚洲一区亚洲| 一区二区精品国产| 欧美在线视频在线播放完整版免费观看| 欧美精品18videos性欧美| 午夜在线成人av| 蜜桃精品一区二区三区| 久久久久国产精品午夜一区| 欧美日韩国产大片| 欧美mv日韩mv国产网站| 国产乱码精品一区二区三区五月婷 | 欧美精品在线观看播放| 久久成人免费网| 久久久久五月天| 久久成人人人人精品欧| 亚洲人成在线观看网站高清| 欧美一区二区三区男人的天堂 | 国产精品视频一区二区三区| 久久久久久久999精品视频| 欧美日韩一区综合| 亚洲第一在线综合网站| 一区视频在线播放| 欧美怡红院视频| 欧美在线视频在线播放完整版免费观看| 亚洲免费在线精品一区| 中文日韩在线| 欧美另类女人| 亚洲美女一区| 夜夜夜久久久| 欧美大片免费久久精品三p| 美日韩精品免费| 亚洲高清免费在线| 美乳少妇欧美精品| 欧美激情精品久久久久久免费印度 | 久久一区二区三区四区五区| 国产日本欧美一区二区三区在线| 欧美一级精品大片| 欧美午夜女人视频在线| 一区二区三区国产盗摄| 午夜精品久久一牛影视| 国产农村妇女毛片精品久久麻豆 | 影音先锋日韩精品| 亚洲天堂久久| 欧美一区深夜视频| 国产综合亚洲精品一区二| 久久aⅴ国产欧美74aaa| 蜜臀久久99精品久久久久久9| 葵司免费一区二区三区四区五区| 亚洲黄网站黄| 欧美激情亚洲国产| 一本一本久久a久久精品综合麻豆 一本一本久久a久久精品牛牛影视 | 亚洲美洲欧洲综合国产一区| av成人免费| 国产精品久久久一区二区三区| 久久久精品久久久久| 亚洲国产成人午夜在线一区| 亚洲人成艺术| 日韩一本二本av| 国产精品香蕉在线观看| 久久九九电影| 亚洲人成网站影音先锋播放| 亚洲一区精彩视频| 黄色成人av在线| 欧美日韩精品免费在线观看视频| 欧美资源在线| 韩国成人精品a∨在线观看| 欧美风情在线观看| 亚洲一区在线播放| 欧美激情第五页| 午夜久久福利| 亚洲国产精品高清久久久| 欧美日韩一区高清| 久久久蜜桃精品| 亚洲综合999| 亚洲国产精品一区二区www在线| 国产视频观看一区| 免费视频亚洲| 亚洲欧美中文另类| 亚洲乱码国产乱码精品精| 久久久久国产精品人| 亚洲午夜电影| 91久久在线观看| 激情视频一区二区| 国产精品一区一区三区| 欧美经典一区二区三区| 香蕉久久精品日日躁夜夜躁| 亚洲精品孕妇| 欧美激情精品久久久六区热门| 亚洲高清一二三区| 国产欧美一区二区三区沐欲| 男人的天堂亚洲在线| 久久本道综合色狠狠五月| 亚洲少妇在线| 亚洲免费观看高清在线观看| 欧美大色视频| 免费成人高清| 蜜臀久久99精品久久久久久9|