




已閱讀5頁,還剩14頁未讀, 繼續(xù)免費閱讀
版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領
文檔簡介
【精品】C+總結(jié) 一、struct字節(jié)對齊問題原則對齊的標準編譯器的對齊模式和struct中的數(shù)據(jù)的最大字節(jié)取的最小值例一#pragma pack (4)#include#include#includeusing namespacestd;void main()struct TEST_1int a;char*b;float c;double d;cout (2)#include#include#includeusing namespacestd;void main()struct TEST_1int a;char b;char list9;double c;cout Int a占4個字節(jié),double c占8個字節(jié),所以整個struct為22例三#pragma pack (4)#include#include#includeusing namespacestd;void main()struct TEST_1int a;char b;struct TEST_2TEST_1tStr1;char a;int b;cout 二、判斷大小端大端(Big-Endian)就是把數(shù)值的高位字節(jié)放在內(nèi)存的低位地址上,把數(shù)值的地位字節(jié)放在內(nèi)存的高位地址上。 小端(Little-Endian)就是把數(shù)字的高位字節(jié)放在高位的地址上,低位字節(jié)放在低位地址上。 #pragma pack (4)#include#include#includeusing namespacestd;void main()unionint a;char b;u;u.a=0x01020304;cout 該問題用另外一種方法實現(xiàn)為#pragma pack (4)#include#include#includeusing namespacestd;void main()int a;char*b;a=0x01020304;b=(char*)&a;coutfunc1();aObj-func2();正確(二)、extern關鍵字1.全局變量extern inta;表示a是在其他文件中定義的一個變量,需要在此引用。 a已在別的文件中,所以不需要再分配空間了。 定義只能有一處,但聲明可有很多處,這些聲明所指都是定義時分配的內(nèi)存空間。 2.使用c的鏈接方式externc表示函數(shù)使用c的鏈接方式,也就是說能被c語言寫的程序調(diào)用。 在C+程序中調(diào)用被C編譯器編譯過的函數(shù)。 為什么要加上externc聲明呢?因為c語言和C+語言的編譯規(guī)則不一樣,所以要告訴系統(tǒng)哪些函數(shù)是用c方式編譯的,哪些函數(shù)是需要用C+方式編譯。 如果你不加externc,在編譯時,系統(tǒng)會提示找不到此函數(shù)。 五、在C+中引用和指針的區(qū)別引用不允許引用空。 必須初始化,一旦初始化不可改變。 引用不在內(nèi)存空間。 引用速度快。 指針可以指向NULL。 指針初始化之后,可以改變。 指針占4個字節(jié)的內(nèi)存空間。 六、C+中的inline內(nèi)聯(lián)函數(shù)首先先說一下C語言中的宏定義,宏定義是在預處理期間起作用的。 定義過的宏直接拉到程序中,而且不做類型檢查,很不安全。 而C+中的內(nèi)聯(lián)函數(shù),也是把內(nèi)聯(lián)函數(shù)直接拉到使用內(nèi)聯(lián)函數(shù)的地方!玉宏定義不同的是,它做類型檢查。 但是有些函數(shù)是不能當做內(nèi)聯(lián)函數(shù)用的!循環(huán)函數(shù)和遞歸函數(shù)就不能用內(nèi)聯(lián)函數(shù),使用內(nèi)聯(lián)函數(shù)就是因為要編譯更快!而這樣展開的話,代碼區(qū)會更長。 反而更浪費時間!同時虛函數(shù)也不可能有inline函數(shù)!因為虛函數(shù)是在執(zhí)行期編譯的,而inline函數(shù)是在預處理期就編譯好的!有的時候很簡單的函數(shù)即使你不定義為內(nèi)聯(lián)函數(shù),編譯器也會自己默認變成內(nèi)聯(lián)函數(shù)。 還有一點就是當有個函數(shù)指針指向內(nèi)聯(lián)函數(shù)之后,內(nèi)聯(lián)函數(shù)是不會擴展的!Void fun()Static obj;在這個函數(shù)fun()第一次調(diào)用的時間,static obj,會被聲明出來。 如果是內(nèi)聯(lián)函數(shù),例如inline void fun()Static obj;。 在另一個函數(shù)中對此此奧用fun(),每次都會橫展開,每次都會產(chǎn)生一個static obj,但是在內(nèi)存中的名字會變掉! 七、對象的內(nèi)存布局 (1)不帶虛函數(shù)的場合在對象的內(nèi)存模型中,只存儲非靜態(tài)的成員變量。 成員函數(shù)無論是不是靜態(tài)的都不存儲在對象的內(nèi)存模型中。 子類繼承父類時,在子類的內(nèi)存模型中,會進行逐位拷貝,把父類的內(nèi)存空間的內(nèi)容原封不動的拷貝下來,然后在接下來的空間中,加入自己的非靜態(tài)成員變量。 接下來看個例子class TestObjBaseprivate:int database1;char database2;class TestObj:public TestObjBasepublic:void fun1();/不在類范圍內(nèi)static voidfun2();/不在類范圍內(nèi)private:int data1;static int data3;/不在類范圍內(nèi)float data2;內(nèi)存布局 (2)包含虛函數(shù)的場合在父類中,會建立一個virtual table表里面弄存儲著很多指向虛函數(shù)首地址的指針,在父類的內(nèi)存空間中會有一個虛指針,指向這個虛表的首地址,另外一般情況下,該虛表格開始處會放置type_info,用于支持runtime typeindentification(RTTI)。 同時,子類的虛表中如果沒有重寫父類的你某個函數(shù),會存儲父類的這個函數(shù)。 接下來看下例子和內(nèi)存模型class Basepublic:virtual voidfun1().;virtual voidfun2().;private:int database1;char database2;class derived:public Basepublic:voidfun1().;/沒有重寫基類的fun2virtual voidfun3().;private:int data1;intdata2;;database14字節(jié)database21字節(jié)3字節(jié)對齊用database14字節(jié)database21字節(jié)3字節(jié)對齊用data14字節(jié)data24字節(jié)TestObjBase TestObj內(nèi)存模型 八、編譯器行為如果你寫一個空類,編譯器會幫你創(chuàng)建一個析構(gòu)函數(shù),一個拷貝構(gòu)造函數(shù)一個該類引用類型的賦值運算符,一對取址運算符。 如果你沒有定義構(gòu)造函數(shù)編譯器會有可能幫你定義一個默認構(gòu)造函數(shù)的。 例如class Emptypublic:Empty();/缺省構(gòu)造函數(shù)Empty(const Empty&rhs);/拷貝構(gòu)造函數(shù)Empty();/析構(gòu)函數(shù)-一般非虛的(除非繼承體系有虛函數(shù))Empty&operator=(const Empty&rhs);/賦值運算符Empty*operator&();/取址運算符const Empty*operator&()const; (1)如果一個類中有指針類型的成員變量,并且沒有自己定義賦值元運算符,那么當這個指針類型的變量通過2個對象指向不同的內(nèi)存,然后這兩個對象做賦值運算,這時因為沒有自定義的operator=可以調(diào)用,c+會生成并調(diào)用一個缺省的operator=操作符。 這個缺省的賦值操作符會執(zhí)行從一個對象的成員到另外一個對象的成員的逐個成員的賦值操作,對指針來說就是逐位拷貝。 那么這兩個指針就指向了同一塊內(nèi)存地址,而必然會有一塊內(nèi)存存儲著原來的信息,但是永遠不能刪除,并且這兩個指針指向的同一塊內(nèi)存,當一個對象調(diào)用了析構(gòu)函database14字節(jié)database21字節(jié)3字節(jié)對齊用database14字節(jié)database21字節(jié)3字節(jié)對齊用data14字節(jié)data24字節(jié)Base derivedType infoBase:fun1Base:fun2vptr baseType infoderived:fun1Base:fun2derived:fun3vptr derived數(shù),就會回收內(nèi)存,那么就有一個指針指向了,內(nèi)容的內(nèi)存。 這樣就造成了內(nèi)存泄露。 例如class stringpublic:string(const char*value);string();./沒有拷貝構(gòu)造函數(shù)和operator=private:char*data;string:string(const char*value)if(value)data=new charstrlen(value)+1;strncpy(data,value,sizeof(data);elsedata=new char1;*data=0;inline string:string()deletedata;如果這樣定義兩個對象string a(hello);string b(world);其結(jié)果就會如下所示a:datahello0b:dataworld0對象a的內(nèi)部是一個指向包含字符串hello的內(nèi)存的指針,對象b的內(nèi)部是一個指向包含字符串world的內(nèi)存的指針。 如果進行下面的賦值b=a;因為沒有自定義的operator=可以調(diào)用,c+會生成并調(diào)用一個缺省的operator=操作符。 這個缺省的賦值操作符會執(zhí)行從a的成員到b的成員的逐個成員的賦值操作,對指針(a.data和b.data)來說就是逐位拷貝。 賦值的結(jié)果如下所示a:data-hello0b:data-/world0這樣world0這個就成了永遠不能刪除的內(nèi)存了。 并且如果a對象調(diào)用析構(gòu)函數(shù)就把hello0內(nèi)存釋放掉了,b對象中的指針就指向了的內(nèi)存區(qū)域。 (2)如果沒有定義拷貝構(gòu)造函數(shù)的話,當在一個成員函數(shù)傳值的時候,會調(diào)用默認拷貝構(gòu)造函數(shù)生成一個原來變量的指針的拷貝,那么當這個成員函數(shù)執(zhí)行完,這個指針拷貝也會釋放空間,這樣會把原來的變量的內(nèi)存空間釋放。 例如void donothing(string localstring)string s=the truthis outthere;donothing(s);因為被傳遞的localstring是一個值,它必須從s通過(缺?。┛截悩?gòu)造函數(shù)進行初始化。 于是localstring擁有了一個s內(nèi)的指針的拷貝。 當donothing結(jié)束運行時,localstring離開了其生存空間,調(diào)用析構(gòu)函數(shù)。 其結(jié)果也將是s包含一個指向localstring早已刪除的內(nèi)存的指針。 解決此類問題方案1只要類里有指針時,就要寫自己版本的拷貝構(gòu)造函數(shù)和賦值操作符函數(shù)。 2可以只聲明這些函數(shù)(聲明為private成員)而不去定義(實現(xiàn))它們。 這就防止了會有人去調(diào)用它們,也防止了編譯器去生成它們。 如class stringprivate:string&operator=(const string&rhs); 九、成員函數(shù)、非成員函數(shù)、友元函數(shù)成員函數(shù)和非成員函數(shù)最大的區(qū)別在于成員函數(shù)可以是虛擬的而非成員函數(shù)不行。 所以,如果有個函數(shù)必須進行動態(tài)綁定,就要采用虛擬函數(shù),而虛擬函數(shù)必定是某個類的成員函數(shù)。 關于這一點就這么簡單。 如果函數(shù)不必是虛擬的,情況就稍微復雜一點。 看下面表示有理數(shù)的一個類class rationalpublic:rational(int numerator=0,int denominator=1);int numerator()const;int denominator()const;private:.;這是一個沒有一點用處的類。 所以,要對它增加加,減,乘等算術操作支持,但是,該用成員函數(shù)還是非成員函數(shù),或者,非成員的友元函數(shù)來實現(xiàn)呢?當拿不定主意的時候,用面向?qū)ο蟮姆椒▉砜紤]!有理數(shù)的乘法是和rational類相聯(lián)系的,所以,寫一個成員函數(shù)把這個操作包到類中。 class rationalpublic:.const rationaloperator*(const rational&rhs)const;現(xiàn)在可以很容易地對有理數(shù)進行乘法操作rational oneeighth(1,8);rational onehalf(1,2);rational result=onehalf*oneeighth;/運行良好result=result*oneeighth;/運行良好但不要滿足,還要支持混合類型操作,比如,rational要能和int相乘。 但當寫下下面的代碼時,只有一半工作result=onehalf*2;/運行良好result=2*onehalf;/出錯!這是一個不好的苗頭。 記得嗎?乘法要滿足交換律。 如果用下面的等價函數(shù)形式重寫上面的兩個例子,問題的原因就很明顯了result=onehalf.operator* (2);/運行良好result=2.operator*(onehalf);/出錯!對象onehalf是一個包含operator*函數(shù)的類的實例,所以編譯器調(diào)用了那個函數(shù)。 而整數(shù)2沒有相應的類,所以沒有operator*成員函數(shù)。 編譯器還會去搜索一個可以象下面這樣調(diào)用的非成員的operator*函數(shù)(即,在某個可見的名字空間里的operator*函數(shù)或全局的operator*函數(shù))result=operator*(2,onehalf);/錯誤!但沒有這樣一個參數(shù)為int和rational的非成員operator*函數(shù),所以搜索失敗。 再看看那個成功的調(diào)用。 它的第二參數(shù)是整數(shù)2,然而rational:operator*期望的參數(shù)卻是rational對象。 怎么回事?為什么2在一個地方可以工作而另一個地方不行?關鍵在于隱式類型轉(zhuǎn)換。 編譯器知道傳的值是int而函數(shù)需要的是rational,但它也同時知道調(diào)用rational的構(gòu)造函數(shù)將int轉(zhuǎn)換成一個合適的rational,所以才有上面成功的調(diào)用。 換句話說,編譯器處理這個調(diào)用時的情形類似下面這樣const rationaltemp (2);/從2產(chǎn)生一個臨時/rational對象result=onehalf*temp;/同onehalf.operator*(temp);當然,只有所涉及的構(gòu)造函數(shù)沒有聲明為explicit的情況下才會這樣,因為explicit構(gòu)造函數(shù)不能用于隱式轉(zhuǎn)換,這正是explicit的含義。 如果rational象下面這樣定義class rationalpublic:explicit rational(int numerator=0,/此構(gòu)造函數(shù)為int denominator=1);/explicit.const rationaloperator*(const rational&rhs)const;.;那么,下面的語句都不能通過編譯result=onehalf*2;/錯誤!result=2*onehalf;/錯誤!這不會為混合運算提供支持,但至少兩條語句的行為一致了。 然而,我們剛才研究的這個類是要設計成可以允許固定類型到rational的隱式轉(zhuǎn)換的這就是為什么rational的構(gòu)造函數(shù)沒有聲明為explicit的原因。 這樣,編譯器將執(zhí)行必要的隱式轉(zhuǎn)換使上面result的第一個賦值語句通過編譯。 實際上,如果需要的話,編譯器會對每個函數(shù)的每個參數(shù)執(zhí)行這種隱式類型轉(zhuǎn)換。 但它只對函數(shù)參數(shù)表中列出的參數(shù)進行轉(zhuǎn)換,決不會對成員函數(shù)所在的對象(即,成員函數(shù)中的*this指針所對應的對象)進行轉(zhuǎn)換。 這就是為什么這個語句可以工作result=onehalf.operator* (2);/converts int-rational而這個語句不行result=2.operator*(onehalf);/不會轉(zhuǎn)換/int-rational第一種情形操作的是列在函數(shù)聲明中的一個參數(shù),而第二種情形不是。 盡管如此,你可能還是想支持混合型的算術操作,而實現(xiàn)的方法現(xiàn)在應該清楚了使operator*成為一個非成員函數(shù),從而允許編譯器對所有的參數(shù)執(zhí)行隱式類型轉(zhuǎn)換class rational./contains nooperator*;const rationaloperator*(const rational&lhs,const rational&rhs)return rational(lhs.numerator()*rhs.numerator(),lhs.denominator()*rhs.denominator();rational onefourth(1,4);rational result;result=onefourth*2;/工作良好result=2*onefourth;/開始工作!這當然是一個完美的結(jié)局,但還有一個擔心operator*應該成為rational類的友元嗎?這種情況下,答案是不必要。 因為operator*可以完全通過類的公有(public)接口來實現(xiàn)。 上面的代碼就是這么做的。 只要能避免使用友元函數(shù)就要避免,因為,和現(xiàn)實生活中差不多,友元帶來的麻煩往往比它對你的幫助多。 然而,很多情況下,不是成員的函數(shù)從概念上說也可能是類接口的一部分,它們需要訪問類的非公有成員的情況也不少。 例如string類。 如果想重載operator和operator和/operator(istream&input);ostream&operatorcin;/合法,但/有違常規(guī)s(istream&input,string&string)deletestring.data;read frominput intosome memory,and makestring.data pointto itreturn input;ostream&operator(ostream&output,const string&string)return output和operator或operator,讓f成為非成員函數(shù)。 如果f還需要訪問c的非公有成員,讓f成為c的友元函數(shù)。 只有非成員函數(shù)對最左邊的參數(shù)進行類型轉(zhuǎn)換。 如果f需要對最左邊的參數(shù)進行類型轉(zhuǎn)換,讓f成為非成員函數(shù)。 如果f還需要訪問c的非公有成員,讓f成為c的友元函數(shù)。 十、explicit關鍵字
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 北京代理記賬合同范本
- 農(nóng)村打井合同范本
- 【復習大串講】【中職專用】高二語文上學期期末綜合測試題(一)(職業(yè)模塊)(原卷版)
- 修理店合同范本
- 原油合同范本
- 公路測量合同范本
- 廠房 合同范本
- 養(yǎng)殖大棚轉(zhuǎn)讓合同范例
- 同城物流合同范本
- 包工地消防安裝合同范本
- 紋繡培訓專業(yè)藝術教程課件
- 雅思詞匯勝經(jīng)電子書
- 西師版三年級下冊數(shù)學教學反思合集
- 足球基礎知識
- GB/T 9793-2012熱噴涂金屬和其他無機覆蓋層鋅、鋁及其合金
- GB/T 5237.1-2017鋁合金建筑型材第1部分:基材
- GB/T 26121-2010可曲撓橡膠接頭
- GB/T 14643.3-2009工業(yè)循環(huán)冷卻水中菌藻的測定方法第3部分:黏泥真菌的測定平皿計數(shù)法
- GB/T 11968-2020蒸壓加氣混凝土砌塊
- DB14T 2586-2022“山西標準”(標識)評價技術規(guī)范 釀造用高粱
- 五年級下冊 第1單元 《古詩三首》第一課時 教案
評論
0/150
提交評論