【精品】C++總結(jié).doc_第1頁(yè)
【精品】C++總結(jié).doc_第2頁(yè)
【精品】C++總結(jié).doc_第3頁(yè)
【精品】C++總結(jié).doc_第4頁(yè)
【精品】C++總結(jié).doc_第5頁(yè)
已閱讀5頁(yè),還剩14頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

【精品】C+總結(jié) 一、struct字節(jié)對(duì)齊問題原則對(duì)齊的標(biāo)準(zhǔn)編譯器的對(duì)齊模式和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個(gè)字節(jié),double c占8個(gè)字節(jié),所以整個(gè)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 該問題用另外一種方法實(shí)現(xiàn)為#pragma pack (4)#include#include#includeusing namespacestd;void main()int a;char*b;a=0x01020304;b=(char*)&a;coutfunc1();aObj-func2();正確(二)、extern關(guān)鍵字1.全局變量extern inta;表示a是在其他文件中定義的一個(gè)變量,需要在此引用。 a已在別的文件中,所以不需要再分配空間了。 定義只能有一處,但聲明可有很多處,這些聲明所指都是定義時(shí)分配的內(nèi)存空間。 2.使用c的鏈接方式externc表示函數(shù)使用c的鏈接方式,也就是說能被c語言寫的程序調(diào)用。 在C+程序中調(diào)用被C編譯器編譯過的函數(shù)。 為什么要加上externc聲明呢?因?yàn)閏語言和C+語言的編譯規(guī)則不一樣,所以要告訴系統(tǒng)哪些函數(shù)是用c方式編譯的,哪些函數(shù)是需要用C+方式編譯。 如果你不加externc,在編譯時(shí),系統(tǒng)會(huì)提示找不到此函數(shù)。 五、在C+中引用和指針的區(qū)別引用不允許引用空。 必須初始化,一旦初始化不可改變。 引用不在內(nèi)存空間。 引用速度快。 指針可以指向NULL。 指針初始化之后,可以改變。 指針占4個(gè)字節(jié)的內(nèi)存空間。 六、C+中的inline內(nèi)聯(lián)函數(shù)首先先說一下C語言中的宏定義,宏定義是在預(yù)處理期間起作用的。 定義過的宏直接拉到程序中,而且不做類型檢查,很不安全。 而C+中的內(nèi)聯(lián)函數(shù),也是把內(nèi)聯(lián)函數(shù)直接拉到使用內(nèi)聯(lián)函數(shù)的地方!玉宏定義不同的是,它做類型檢查。 但是有些函數(shù)是不能當(dāng)做內(nèi)聯(lián)函數(shù)用的!循環(huán)函數(shù)和遞歸函數(shù)就不能用內(nèi)聯(lián)函數(shù),使用內(nèi)聯(lián)函數(shù)就是因?yàn)橐幾g更快!而這樣展開的話,代碼區(qū)會(huì)更長(zhǎng)。 反而更浪費(fèi)時(shí)間!同時(shí)虛函數(shù)也不可能有inline函數(shù)!因?yàn)樘摵瘮?shù)是在執(zhí)行期編譯的,而inline函數(shù)是在預(yù)處理期就編譯好的!有的時(shí)候很簡(jiǎn)單的函數(shù)即使你不定義為內(nèi)聯(lián)函數(shù),編譯器也會(huì)自己默認(rèn)變成內(nèi)聯(lián)函數(shù)。 還有一點(diǎn)就是當(dāng)有個(gè)函數(shù)指針指向內(nèi)聯(lián)函數(shù)之后,內(nèi)聯(lián)函數(shù)是不會(huì)擴(kuò)展的!Void fun()Static obj;在這個(gè)函數(shù)fun()第一次調(diào)用的時(shí)間,static obj,會(huì)被聲明出來。 如果是內(nèi)聯(lián)函數(shù),例如inline void fun()Static obj;。 在另一個(gè)函數(shù)中對(duì)此此奧用fun(),每次都會(huì)橫展開,每次都會(huì)產(chǎn)生一個(gè)static obj,但是在內(nèi)存中的名字會(huì)變掉! 七、對(duì)象的內(nèi)存布局 (1)不帶虛函數(shù)的場(chǎng)合在對(duì)象的內(nèi)存模型中,只存儲(chǔ)非靜態(tài)的成員變量。 成員函數(shù)無論是不是靜態(tài)的都不存儲(chǔ)在對(duì)象的內(nèi)存模型中。 子類繼承父類時(shí),在子類的內(nèi)存模型中,會(huì)進(jìn)行逐位拷貝,把父類的內(nèi)存空間的內(nèi)容原封不動(dòng)的拷貝下來,然后在接下來的空間中,加入自己的非靜態(tài)成員變量。 接下來看個(gè)例子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ù)的場(chǎng)合在父類中,會(huì)建立一個(gè)virtual table表里面弄存儲(chǔ)著很多指向虛函數(shù)首地址的指針,在父類的內(nèi)存空間中會(huì)有一個(gè)虛指針,指向這個(gè)虛表的首地址,另外一般情況下,該虛表格開始處會(huì)放置type_info,用于支持runtime typeindentification(RTTI)。 同時(shí),子類的虛表中如果沒有重寫父類的你某個(gè)函數(shù),會(huì)存儲(chǔ)父類的這個(gè)函數(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é)對(duì)齊用database14字節(jié)database21字節(jié)3字節(jié)對(duì)齊用data14字節(jié)data24字節(jié)TestObjBase TestObj內(nèi)存模型 八、編譯器行為如果你寫一個(gè)空類,編譯器會(huì)幫你創(chuàng)建一個(gè)析構(gòu)函數(shù),一個(gè)拷貝構(gòu)造函數(shù)一個(gè)該類引用類型的賦值運(yùn)算符,一對(duì)取址運(yùn)算符。 如果你沒有定義構(gòu)造函數(shù)編譯器會(huì)有可能幫你定義一個(gè)默認(rèn)構(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);/賦值運(yùn)算符Empty*operator&();/取址運(yùn)算符const Empty*operator&()const; (1)如果一個(gè)類中有指針類型的成員變量,并且沒有自己定義賦值元運(yùn)算符,那么當(dāng)這個(gè)指針類型的變量通過2個(gè)對(duì)象指向不同的內(nèi)存,然后這兩個(gè)對(duì)象做賦值運(yùn)算,這時(shí)因?yàn)闆]有自定義的operator=可以調(diào)用,c+會(huì)生成并調(diào)用一個(gè)缺省的operator=操作符。 這個(gè)缺省的賦值操作符會(huì)執(zhí)行從一個(gè)對(duì)象的成員到另外一個(gè)對(duì)象的成員的逐個(gè)成員的賦值操作,對(duì)指針來說就是逐位拷貝。 那么這兩個(gè)指針就指向了同一塊內(nèi)存地址,而必然會(huì)有一塊內(nèi)存存儲(chǔ)著原來的信息,但是永遠(yuǎn)不能刪除,并且這兩個(gè)指針指向的同一塊內(nèi)存,當(dāng)一個(gè)對(duì)象調(diào)用了析構(gòu)函database14字節(jié)database21字節(jié)3字節(jié)對(duì)齊用database14字節(jié)database21字節(jié)3字節(jié)對(duì)齊用data14字節(jié)data24字節(jié)Base derivedType infoBase:fun1Base:fun2vptr baseType infoderived:fun1Base:fun2derived:fun3vptr derived數(shù),就會(huì)回收內(nèi)存,那么就有一個(gè)指針指向了,內(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;如果這樣定義兩個(gè)對(duì)象string a(hello);string b(world);其結(jié)果就會(huì)如下所示a:datahello0b:dataworld0對(duì)象a的內(nèi)部是一個(gè)指向包含字符串hello的內(nèi)存的指針,對(duì)象b的內(nèi)部是一個(gè)指向包含字符串world的內(nèi)存的指針。 如果進(jìn)行下面的賦值b=a;因?yàn)闆]有自定義的operator=可以調(diào)用,c+會(huì)生成并調(diào)用一個(gè)缺省的operator=操作符。 這個(gè)缺省的賦值操作符會(huì)執(zhí)行從a的成員到b的成員的逐個(gè)成員的賦值操作,對(duì)指針(a.data和b.data)來說就是逐位拷貝。 賦值的結(jié)果如下所示a:data-hello0b:data-/world0這樣world0這個(gè)就成了永遠(yuǎn)不能刪除的內(nèi)存了。 并且如果a對(duì)象調(diào)用析構(gòu)函數(shù)就把hello0內(nèi)存釋放掉了,b對(duì)象中的指針就指向了的內(nèi)存區(qū)域。 (2)如果沒有定義拷貝構(gòu)造函數(shù)的話,當(dāng)在一個(gè)成員函數(shù)傳值的時(shí)候,會(huì)調(diào)用默認(rèn)拷貝構(gòu)造函數(shù)生成一個(gè)原來變量的指針的拷貝,那么當(dāng)這個(gè)成員函數(shù)執(zhí)行完,這個(gè)指針拷貝也會(huì)釋放空間,這樣會(huì)把原來的變量的內(nèi)存空間釋放。 例如void donothing(string localstring)string s=the truthis outthere;donothing(s);因?yàn)楸粋鬟f的localstring是一個(gè)值,它必須從s通過(缺?。┛截悩?gòu)造函數(shù)進(jìn)行初始化。 于是localstring擁有了一個(gè)s內(nèi)的指針的拷貝。 當(dāng)donothing結(jié)束運(yùn)行時(shí),localstring離開了其生存空間,調(diào)用析構(gòu)函數(shù)。 其結(jié)果也將是s包含一個(gè)指向localstring早已刪除的內(nèi)存的指針。 解決此類問題方案1只要類里有指針時(shí),就要寫自己版本的拷貝構(gòu)造函數(shù)和賦值操作符函數(shù)。 2可以只聲明這些函數(shù)(聲明為private成員)而不去定義(實(shí)現(xiàn))它們。 這就防止了會(huì)有人去調(diào)用它們,也防止了編譯器去生成它們。 如class stringprivate:string&operator=(const string&rhs); 九、成員函數(shù)、非成員函數(shù)、友元函數(shù)成員函數(shù)和非成員函數(shù)最大的區(qū)別在于成員函數(shù)可以是虛擬的而非成員函數(shù)不行。 所以,如果有個(gè)函數(shù)必須進(jìn)行動(dòng)態(tài)綁定,就要采用虛擬函數(shù),而虛擬函數(shù)必定是某個(gè)類的成員函數(shù)。 關(guān)于這一點(diǎn)就這么簡(jiǎn)單。 如果函數(shù)不必是虛擬的,情況就稍微復(fù)雜一點(diǎn)。 看下面表示有理數(shù)的一個(gè)類class rationalpublic:rational(int numerator=0,int denominator=1);int numerator()const;int denominator()const;private:.;這是一個(gè)沒有一點(diǎn)用處的類。 所以,要對(duì)它增加加,減,乘等算術(shù)操作支持,但是,該用成員函數(shù)還是非成員函數(shù),或者,非成員的友元函數(shù)來實(shí)現(xiàn)呢?當(dāng)拿不定主意的時(shí)候,用面向?qū)ο蟮姆椒▉砜紤]!有理數(shù)的乘法是和rational類相聯(lián)系的,所以,寫一個(gè)成員函數(shù)把這個(gè)操作包到類中。 class rationalpublic:.const rationaloperator*(const rational&rhs)const;現(xiàn)在可以很容易地對(duì)有理數(shù)進(jìn)行乘法操作rational oneeighth(1,8);rational onehalf(1,2);rational result=onehalf*oneeighth;/運(yùn)行良好result=result*oneeighth;/運(yùn)行良好但不要滿足,還要支持混合類型操作,比如,rational要能和int相乘。 但當(dāng)寫下下面的代碼時(shí),只有一半工作result=onehalf*2;/運(yùn)行良好result=2*onehalf;/出錯(cuò)!這是一個(gè)不好的苗頭。 記得嗎?乘法要滿足交換律。 如果用下面的等價(jià)函數(shù)形式重寫上面的兩個(gè)例子,問題的原因就很明顯了result=onehalf.operator* (2);/運(yùn)行良好result=2.operator*(onehalf);/出錯(cuò)!對(duì)象onehalf是一個(gè)包含operator*函數(shù)的類的實(shí)例,所以編譯器調(diào)用了那個(gè)函數(shù)。 而整數(shù)2沒有相應(yīng)的類,所以沒有operator*成員函數(shù)。 編譯器還會(huì)去搜索一個(gè)可以象下面這樣調(diào)用的非成員的operator*函數(shù)(即,在某個(gè)可見的名字空間里的operator*函數(shù)或全局的operator*函數(shù))result=operator*(2,onehalf);/錯(cuò)誤!但沒有這樣一個(gè)參數(shù)為int和rational的非成員operator*函數(shù),所以搜索失敗。 再看看那個(gè)成功的調(diào)用。 它的第二參數(shù)是整數(shù)2,然而rational:operator*期望的參數(shù)卻是rational對(duì)象。 怎么回事?為什么2在一個(gè)地方可以工作而另一個(gè)地方不行?關(guān)鍵在于隱式類型轉(zhuǎn)換。 編譯器知道傳的值是int而函數(shù)需要的是rational,但它也同時(shí)知道調(diào)用rational的構(gòu)造函數(shù)將int轉(zhuǎn)換成一個(gè)合適的rational,所以才有上面成功的調(diào)用。 換句話說,編譯器處理這個(gè)調(diào)用時(shí)的情形類似下面這樣const rationaltemp (2);/從2產(chǎn)生一個(gè)臨時(shí)/rational對(duì)象result=onehalf*temp;/同onehalf.operator*(temp);當(dāng)然,只有所涉及的構(gòu)造函數(shù)沒有聲明為explicit的情況下才會(huì)這樣,因?yàn)閑xplicit構(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;/錯(cuò)誤!result=2*onehalf;/錯(cuò)誤!這不會(huì)為混合運(yùn)算提供支持,但至少兩條語句的行為一致了。 然而,我們剛才研究的這個(gè)類是要設(shè)計(jì)成可以允許固定類型到rational的隱式轉(zhuǎn)換的這就是為什么rational的構(gòu)造函數(shù)沒有聲明為explicit的原因。 這樣,編譯器將執(zhí)行必要的隱式轉(zhuǎn)換使上面result的第一個(gè)賦值語句通過編譯。 實(shí)際上,如果需要的話,編譯器會(huì)對(duì)每個(gè)函數(shù)的每個(gè)參數(shù)執(zhí)行這種隱式類型轉(zhuǎn)換。 但它只對(duì)函數(shù)參數(shù)表中列出的參數(shù)進(jìn)行轉(zhuǎn)換,決不會(huì)對(duì)成員函數(shù)所在的對(duì)象(即,成員函數(shù)中的*this指針?biāo)鶎?duì)應(yīng)的對(duì)象)進(jìn)行轉(zhuǎn)換。 這就是為什么這個(gè)語句可以工作result=onehalf.operator* (2);/converts int-rational而這個(gè)語句不行result=2.operator*(onehalf);/不會(huì)轉(zhuǎn)換/int-rational第一種情形操作的是列在函數(shù)聲明中的一個(gè)參數(shù),而第二種情形不是。 盡管如此,你可能還是想支持混合型的算術(shù)操作,而實(shí)現(xiàn)的方法現(xiàn)在應(yīng)該清楚了使operator*成為一個(gè)非成員函數(shù),從而允許編譯器對(duì)所有的參數(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;/開始工作!這當(dāng)然是一個(gè)完美的結(jié)局,但還有一個(gè)擔(dān)心operator*應(yīng)該成為rational類的友元嗎?這種情況下,答案是不必要。 因?yàn)閛perator*可以完全通過類的公有(public)接口來實(shí)現(xiàn)。 上面的代碼就是這么做的。 只要能避免使用友元函數(shù)就要避免,因?yàn)?,和現(xiàn)實(shí)生活中差不多,友元帶來的麻煩往往比它對(duì)你的幫助多。 然而,很多情況下,不是成員的函數(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ù)對(duì)最左邊的參數(shù)進(jìn)行類型轉(zhuǎn)換。 如果f需要對(duì)最左邊的參數(shù)進(jìn)行類型轉(zhuǎn)換,讓f成為非成員函數(shù)。 如果f還需要訪問c的非公有成員,讓f成為c的友元函數(shù)。 十、explicit關(guān)鍵字

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論