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

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>
            欧美一区二视频| 极品少妇一区二区| 亚洲自拍都市欧美小说| 一区二区欧美日韩| 国产精品久久综合| 久久深夜福利| 欧美激情按摩| 亚洲欧美综合精品久久成人| 午夜精品久久久99热福利| 一区二区三区四区五区精品视频| 欧美黄色免费| 欧美日韩综合另类| 久久狠狠亚洲综合| 欧美大片一区| 欧美一级播放| 蜜臀av性久久久久蜜臀aⅴ| 9色国产精品| 西西裸体人体做爰大胆久久久| 激情婷婷久久| 一区二区三区久久网| 国产主播在线一区| 日韩一区二区免费看| 国产在线精品二区| 一本色道久久综合| 影音先锋亚洲视频| 黄色工厂这里只有精品| 久久久噜噜噜久久| 99精品视频免费在线观看| 国产伦理精品不卡| 亚洲国产精品热久久| 国产精品黄色| 欧美黄色大片网站| 国产一区二区三区日韩| 亚洲另类一区二区| 樱桃国产成人精品视频| 亚洲一区中文字幕在线观看| 亚洲精品视频免费| 欧美在线观看一区| 亚洲免费一在线| 老鸭窝毛片一区二区三区| 欧美亚洲网站| 欧美日韩激情网| 免费视频一区| 国内精品久久久久影院优| 亚洲婷婷在线| 亚洲无人区一区| 欧美国产精品日韩| 欧美va日韩va| 狠狠干成人综合网| 性做久久久久久久久| 亚洲欧美另类国产| 欧美视频精品一区| 亚洲精品久久久久久久久久久久| 亚洲高清在线观看| 久久国产精品一区二区三区四区| 午夜精品久久久久久久99樱桃| 欧美精品激情| 亚洲精品视频在线| 日韩亚洲欧美综合| 欧美精品一区在线播放| 亚洲国产成人在线| 亚洲三级免费电影| 欧美国产在线电影| 亚洲精品少妇| 日韩亚洲视频在线| 欧美日韩一区不卡| 夜夜嗨av一区二区三区四季av| 中文在线资源观看网站视频免费不卡 | 亚洲在线观看免费| 亚洲欧美日韩一区二区| 国产精品久久久久77777| 亚洲色诱最新| 久久国产一区二区| 国产一区欧美日韩| 玖玖综合伊人| 亚洲精品国产精品国自产观看| 亚洲精品在线电影| 欧美日韩综合网| 亚洲欧美在线观看| 欧美成ee人免费视频| 亚洲精品中文字幕有码专区| 欧美—级在线免费片| 99精品热视频| 久久久久国产精品人| 看片网站欧美日韩| 蜜乳av另类精品一区二区| 亚洲韩国日本中文字幕| 亚洲区欧美区| 亚洲免费影院| 在线观看欧美激情| 欧美午夜激情在线| 久久精品国产久精国产爱| 亚洲国产成人在线| 欧美在线观看一区二区| 1024成人| 国产精品久久毛片a| 久久日韩精品| 亚洲一区二区三区在线观看视频| 久久久久久久综合日本| 亚洲伦理在线观看| 国产深夜精品| 欧美精品在线极品| 久久99伊人| 亚洲网友自拍| 亚洲成人在线视频网站| 精品成人一区二区三区| 欧美精品国产一区二区| 欧美中文字幕在线播放| 亚洲精品日韩精品| 久久婷婷影院| 亚洲小说欧美另类社区| 在线成人h网| 国产欧美精品久久| 欧美日韩一区自拍| 老牛影视一区二区三区| 亚洲字幕一区二区| 亚洲免费观看高清在线观看| 久久亚洲精品网站| 午夜精品久久久久久久99黑人| 亚洲国产精品一区制服丝袜| 国产女优一区| 欧美三区在线视频| 欧美韩国在线| 免费看成人av| 久久人人爽人人爽爽久久| 欧美在线观看一区| 亚洲欧美在线视频观看| 一区二区高清在线观看| 91久久综合| 亚洲国产日韩在线| 欧美国产综合一区二区| 噜噜噜躁狠狠躁狠狠精品视频| 欧美一区二区三区另类| 亚洲小少妇裸体bbw| 亚洲午夜高清视频| 一区二区三区www| 日韩视频一区二区三区在线播放免费观看| 国产一区二区三区高清| 国产午夜亚洲精品羞羞网站| 国产乱码精品一区二区三区av| 欧美网站大全在线观看| 欧美日韩午夜| 欧美性大战久久久久久久| 国产精品护士白丝一区av| 国产精品看片你懂得| 国产美女精品| 国内精品久久久| 在线观看不卡| 亚洲黄色成人网| 亚洲精选91| 亚洲永久精品国产| 欧美中文日韩| 蜜桃久久av一区| 亚洲黄色三级| 亚洲性色视频| 久久福利一区| 男女视频一区二区| 欧美日韩伦理在线免费| 欧美性淫爽ww久久久久无| 国产精品一区二区男女羞羞无遮挡| 国产精品日韩一区| 国产精品久久久久高潮| 99国内精品久久久久久久软件| 日韩亚洲欧美一区二区三区| 亚洲一区激情| 久久久五月婷婷| 亚洲激情av在线| 亚洲性图久久| 美女福利精品视频| 欧美午夜一区二区| 黄色成人av在线| 在线午夜精品自拍| 久久久噜噜噜久久人人看| 亚洲国产成人一区| 亚洲欧美日韩成人| 另类春色校园亚洲| 国产精品久久久久高潮| 1769国内精品视频在线播放| 在线性视频日韩欧美| 久久精品国产v日韩v亚洲| 欧美激情第一页xxx| 一区二区日本视频| 奶水喷射视频一区| 国产三级精品三级| 一本一本a久久| 免费成人av| 亚洲欧美清纯在线制服| 欧美成年人视频| 国语自产偷拍精品视频偷| 亚洲视频成人| 亚洲国产精品传媒在线观看| 亚洲欧美另类在线| 欧美日韩情趣电影| 亚洲国产欧美久久| 久久久久国色av免费看影院| 一区二区久久久久久| 欧美国产精品久久| 91久久精品国产91久久性色tv| 久久电影一区| 亚洲网站在线|