版權說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權,請進行舉報或認領
文檔簡介
主講教師:游洪躍個人主頁:http:///~youhongyue高級語言程序設計II四川大學計算機學院四川大學計算機學院1教材:《C++面向對象程序設計》李濤主編游洪躍陳良銀李琳等編高等教育出版社2006年2月出版2本書內(nèi)容
第1章緒論第2章C++類和對象第3章繼承第4章多態(tài)性第5章模板第6章C++常見問題第7章VisualC++編程基礎第8章對話框、常用消息、菜單和工具條第9章單文檔界面和多文檔界面第10章圖形設備接口實驗(待安排)3提綱動態(tài)內(nèi)存管理技術第六章C++常見問題ARMVectorTableFIQIRQ(Reserved)DataAbortPrefetchAbortSoftwareInterruptUndefinedInstructionReset0x1C0x180x140x100x0C0x080x040x00132Const的使用內(nèi)聯(lián)函數(shù)的使用使用引用4類型轉換5異常處理6命名空間74本章將討論C++中比較常見的一些問題,這部分問題比較繁瑣,但也是C++中比較核心的問題。比如:動態(tài)內(nèi)存的使用、const的使用等。編制程序時必須涉及這些內(nèi)容。內(nèi)存不就是存放數(shù)據(jù)的空間嗎?56.1內(nèi)聯(lián)函數(shù)的使用內(nèi)聯(lián)與非內(nèi)聯(lián)函數(shù)的主要區(qū)別就在于編譯時的處理方式不同。在執(zhí)行效率和空間占用上有差異。我不喜歡內(nèi)聯(lián)函數(shù)行嗎?66.1.1內(nèi)聯(lián)函數(shù)引入的原因調(diào)用函數(shù)時,要跳到函數(shù)的起始地址去執(zhí)行,執(zhí)行完函數(shù)的代碼后,再返回到調(diào)用點繼續(xù)執(zhí)行。這種跳轉操作需要保存現(xiàn)場及返回地址;返回時,又需要恢復現(xiàn)場。函數(shù)調(diào)用需要一定的時間開銷和空間開銷,這會影響程序的執(zhí)行效率。外聯(lián)開銷7對內(nèi)聯(lián)函數(shù),編譯器會在程序出現(xiàn)內(nèi)聯(lián)函數(shù)調(diào)用的地方用函數(shù)體直接進行替換。目標程序將不存在調(diào)用問題,也就不會產(chǎn)生跳轉的問題,自然就不存在函數(shù)調(diào)用所需要的時間和空間開銷。在編譯時用函數(shù)代碼替換到調(diào)用處,如果函數(shù)代碼長度比較長,超過了跳轉語句所占空間的長度,這自然會增加整個程序的代碼量,進而增加了空間的開銷。實質是用空間換時間。86.1.2內(nèi)聯(lián)函數(shù)的定義例6_1:smain6_1.cpp
//1、全局函數(shù)定義為內(nèi)聯(lián)函數(shù)inlinedoubleShow1(doubledX) { returndX*dX;}9//2、在類聲明體內(nèi)實現(xiàn)的函數(shù)不用inline關鍵字,自動是內(nèi)聯(lián)函數(shù)。 doubleShow2(doubledX)const
{ returndX*dX; }10//3、在函數(shù)聲明處可加可不加inline關鍵字。
doubleShow3(doubledX)const; //4、但在實現(xiàn)處必須加inline關鍵字inlinedoubleCPerson::Show3(doubledX)const{ returndX*dX;}11內(nèi)聯(lián)函數(shù)使用時注意以下幾點。1、在內(nèi)聯(lián)函數(shù)中不允許用循環(huán)語句、開關語句和遞歸調(diào)用語句等。2、內(nèi)聯(lián)函數(shù)的定義必須出現(xiàn)在第一次調(diào)用內(nèi)聯(lián)函數(shù)之前。3、在類內(nèi)部定義并實現(xiàn)的成員函數(shù)自動是內(nèi)聯(lián)函數(shù),但在類內(nèi)定義成員函數(shù)時,如果使用了for()、while()、do{}while()、switch()等語句,該成員函數(shù)會自動轉為非內(nèi)聯(lián)函數(shù)。4、內(nèi)聯(lián)函數(shù)中不能夠有靜態(tài)數(shù)據(jù)。5、內(nèi)聯(lián)函數(shù)中不能夠有數(shù)組說明。126.1.3內(nèi)聯(lián)和非內(nèi)聯(lián)函數(shù)的選擇使用內(nèi)聯(lián)函數(shù)時間開銷的減少,以空間的消耗為代價,而且執(zhí)行效率的提高也不是絕對的。在決定使用內(nèi)聯(lián)函數(shù)時要進行適當?shù)娜∩帷2皇撬械暮瘮?shù)都適合采用內(nèi)聯(lián)函數(shù)。構造函數(shù)和析構函數(shù)常常就不適合內(nèi)聯(lián),這是因為構造函數(shù)和析構函數(shù)在編譯時,往往會被編譯器附加一大堆代碼。全部內(nèi)聯(lián)可以嗎?13看看CStudent類的構造函數(shù):例6_2:構造函數(shù)、析構函數(shù)往往不適合作內(nèi)聯(lián)函數(shù)。smain6_2.cpp
構造函數(shù)、析構函數(shù)最好不要內(nèi)聯(lián)。14CStudent()構造函數(shù)看起來是空的,但它可能含有相當多的代碼(與編譯器的設計有關)。CStudent的構造函數(shù),需要構建4000字節(jié)的空間,并且還需要按照基類的要求初始化這些空間,因此它包含了一個復雜的創(chuàng)建過程。構造函數(shù)和析構函數(shù)最好都在類內(nèi)聲明,類外實現(xiàn)。一般來說,實際編程時最好是不要內(nèi)聯(lián)任何函數(shù),除非函數(shù)確實很小很簡單。不要內(nèi)聯(lián)任何函數(shù)156.2const的使用const意味著分配了一塊不可改變的內(nèi)存。用const定義或說明常類型量時必須初始化。常類型量,也就是常量。const更重要的用途則在于說明函數(shù)參數(shù)以及函數(shù)返回類型。函數(shù)參數(shù)16const主要有以下幾種用法:1、const說明值常量。2、const說明指針。3、const說明函數(shù)參數(shù)及其返回值。4、const說明類中的常量和成員函數(shù)。Const與指針176.2.1const說明值常量1、說明符號常量,表明符號代表的是一個常量,說明格式如下:doubleconstPI=12;constdoublePI=12; const在前、在后定義都可以。182、說明數(shù)組常量,說明格式如下:constint
I_ARRAY[]={3,2,1};3、說明對象常量,說明格式如下:constCInline1
oC1,oC2;在一排逗號隔開的變量中,只需要一個const就行了19const與C語言"#define"的差別:#definePI3.14無參宏不是符號常量,它沒有數(shù)據(jù)類型,沒有值,在內(nèi)存中不分配地址。它是在預處理時作宏替換,不作類型檢查。而const定義的常量是符號常量,有數(shù)據(jù)類型,有值,且其值不可改變,在內(nèi)存中有地址,編譯時要作類型檢查。206.2.2const與指針指針涉及三個東西:一個是指針變量本身;另一個是指針——指針變量中所存放的值;再一個就是指針所指向的對象。21指針其實就是地址,它代表的是指針變量中存放的地址值;而指針變量是指用來存放指針的一個變量,它用來存放地址;注意:指針變量本身也有地址,有存儲單元;指針所指向的對象是指那片空間所“存放的東西”。指針變量本身的地址,與指針變量所指向的對象的存儲地址是兩個不同的地址。2223const和指針變量的典型組合有以下三種情況:1、指向常量的指針——”constint*p;”2、常指針——”char*constpc="a";”3、指向常量的常指針——“constchar*constpc="a";”太過分了,如此變化多端?。。?!24
const
int*p;char*constpc="a";
constchar*constpc="a";畫一條垂直線穿過指針聲明中的星號(*)位置。如果const出現(xiàn)在線的左邊,則指針指向的對象為常量;如果const出現(xiàn)在線的右邊,則指針本身為常量;如果const在線的兩邊都出現(xiàn),則二者都是常量,是指向常量的常指針。251指向常量的指針指針指向一個不可改變的量。指向常量。在聲明時可以不初始化。該指針可以指向這個常量,也可以指向另一個常量。指針變量里的指針值是可以改變的;但某一個具體指針值(即:某個指針)所指向的那個對象則是不可以改變的。對象不可改變。26它也可以指向變量;從指針角度而言,所指向的是一個常量,通過該指針不能修改它所指向的對象;該指針變量可以存放常量地址也可以存放變量地址。對象不可改變。27constchar*pc="ABCD";
pc[3]='a'; //不可以。pc=“EFGH”; //可以//step是一個指向常量的指針數(shù)組constchar*step[3]={"left","right","top"};step[2]="skip"; //可以。step[2][1]='i'; //不可以。282常指針
<類型>*const<指針名>[=<初值>;]指針變量里面存放的是個常量,稱為常指針,指針變量里面裝的是一個固定值,在定義時必須初始化。常指針一旦初始化后,不能夠再指向其他內(nèi)存單元。通過常指針可以修改它所指向的內(nèi)存單元的內(nèi)容,也就是修改常指針所指向的對象。29char*constpc="ABCD"; //常指針pc[3]='a'; //可以。pc="EFGH"; //不可以//step是一個常指針數(shù)組char*conststep[3]={"left","right","top"};step[2]="skip"; //不可以。step[2][1]='i'; //可以。303指向常量的常指針指針本身及指針所指向的對象都不可改變。二者都要聲明為const。在聲明時必須初始化。指針本身及其指向的對象均不能改變。constchar*constpc="asdf";
pc[3]='a'; //不可以。pc="ABCD"; //不可以。316.2.3const說明函數(shù)參數(shù)和返回值是const最重要的應用。在值傳遞場合不必用const。用const去修飾用指針和引用傳遞的函數(shù)參數(shù),是安全的。const修飾函數(shù)的返回值。安全的32voidFunc(constchar*lpszChar);voidFunc(charconst*lpszChar);//以上二者等價。//參數(shù)是對象的常引用,返回值也是一個對象的常引用。constCStudent&Func(const
CStudent&oCStudent); 對返回值使用const也有可能提高函數(shù)的安全性和效率。336.2.4類中的const在類中,const的使用也比較廣。它可以用于修飾類中的成員函數(shù)和成員數(shù)據(jù)。主要應用341常成員函數(shù)不可以改變對象數(shù)據(jù)成員的函數(shù)。在一般成員函數(shù)后面加上const即可。1、用const關鍵詞修飾一個成員函數(shù),說明該成員函數(shù)是“只讀”的。2、只有常成員函數(shù)可以操作常對象,常對象只能調(diào)用常成員函數(shù)(const成員函數(shù))。3、一般對象不但可以調(diào)用一般成員函數(shù),也可以調(diào)用常成員函數(shù)。35例6_3:常對象只能夠調(diào)用常成員函數(shù),不能夠調(diào)用一般成員函數(shù),而一般對象可以調(diào)用所有的成員函數(shù)。s6_3\sclass6_3_T.hs6_3\sclass6_3_point.cpp
s6_3\smain6_3.cpp
一般成員函數(shù)調(diào)用:12一般成員函數(shù)調(diào)用:23
常成員函數(shù)調(diào)用:33
36例子表明:僅在const方面有不同的成員函數(shù)是可以重載的,編譯器能夠正確區(qū)分這兩個函數(shù)。而對調(diào)用對象來說,一般對象優(yōu)先調(diào)用重載的一般函數(shù),其次才是const函數(shù);常對象(const對象)則只能夠調(diào)用const函數(shù),不能夠調(diào)用一般函數(shù)。對于一般對象,當調(diào)用一般成員函數(shù)不成功時,系統(tǒng)自動會轉入對常成員函數(shù)的調(diào)用。372常數(shù)據(jù)成員若一個數(shù)據(jù)成員的前面用了關鍵詞const修飾符,則該數(shù)據(jù)成員為常數(shù)據(jù)成員。const型的數(shù)據(jù)必須初始化,且不能修改,它是常數(shù)據(jù)成員。常數(shù)據(jù)成員的初始化方式——在定義對象時,通過在構造函數(shù)后面加上成員初始化列表來完成的。smain6_4.cpp
38classCPoint //CPoint類{private:
intm_x; //x坐標
constintm_y; //y坐標,常數(shù)據(jù)成員
staticconstintm_z; //z坐標,靜態(tài)常數(shù)據(jù)成員};constint
CPoint::m_z=0; //靜態(tài)數(shù)據(jù)成員的初始化方式。//構造函數(shù),m_y采用了初始化表的方式初始化。CPoint::CPoint(intx,inty):m_y(y)
{
m_x=x; //正確。
//m_y=y; //錯。}39在CPoint中設置了空間坐標中的m_x、m_y和m_z坐標。分別把它們設置成一般數(shù)據(jù)成員、常數(shù)據(jù)成員和靜態(tài)常數(shù)據(jù)成員。由于類型不同,它們所采用的初始化方式是很不一樣的。在設計構造函數(shù)時,最好對一般成員數(shù)據(jù)也采用初始化表的方式進行初始化。這樣效率最高。403常對象常對象就是其值不可改變的對象。它是只可以取值不可以修改的對象。常對象一旦建立并初始化以后,只可以通過常成員函數(shù)來訪問它。constCPointocCPoint3(3,3);
416.3動態(tài)內(nèi)存管理技術動態(tài)對象就是程序在運行過程中在動態(tài)內(nèi)存中建立的對象。這類對象需要用戶自己使用new運算符創(chuàng)建,使用delete運算符釋放,需要用戶自己管理。堆棧靜態(tài)內(nèi)存426.3.1內(nèi)存的幾種分配方式計算機內(nèi)存通常具有三種組織方式:堆、棧和靜態(tài)內(nèi)存。1、在靜態(tài)存儲區(qū)中分配。靜態(tài)存儲區(qū)中的變量空間在編譯時分配。靜態(tài)內(nèi)存區(qū)中的變量在程序的整個運行期間都存在。其生命周期貫穿整個程序的運行周期。例如全局變量,static變量等在這個區(qū)間分配。432、在棧上分配。自動變量等局部變量在棧上分配存儲空間。函數(shù)內(nèi)的局部變量在棧上分配存儲單元。它的生命周期與函數(shù)的執(zhí)行時間相同。當函數(shù)執(zhí)行結束時這些存儲單元會被自動釋放,其生命周期也就完結了。443、在堆上分配,亦稱動態(tài)內(nèi)存分配。動態(tài)內(nèi)存由程序員自己負責管理。運行時用new申請內(nèi)存。程序員負責在不需要時用delete釋放內(nèi)存。比拉登還麻煩。容易出問題。456.3.2使用new和delete分配和釋放動態(tài)內(nèi)存malloc()與free()標準庫函數(shù);new/delete運算符(不是庫函數(shù))。malloc()/free()功能有限。用戶自定義類型在創(chuàng)建對象時要執(zhí)行構造函數(shù),對象在消亡之前要執(zhí)行析構函數(shù)。而且是自動執(zhí)行的。所以,C++使用能完成動態(tài)內(nèi)存分配和初始化工作的運算符new,及能完成清理與釋放內(nèi)存工作的運算符delete來管理動態(tài)內(nèi)存。46new運算符new用來動態(tài)地分配存儲空間。它能夠自動計算要分配的存儲空間大小并能返回正確的指針類型。若返回值為NULL,則表示動態(tài)內(nèi)存分配不成功。在用new申請動態(tài)內(nèi)存后,一定要判斷動態(tài)內(nèi)存是否分配成功。if(p!=NULL)47int*pInt1,*pInt2;pInt1=newint; //new運算返回一整數(shù)單元的地址pInt2=newint(200); //new一個int單元,并將其初始化為200。int*pInt3,(*pInt4)[3];
pInt3=newint[10];//new運算返回一整數(shù)單元的地址,有10個這樣的單元。pInt4=newint[2][3]; //new運算返回每行為3個元素的行地址CPoint*poCPoint;poCPoint=newCPoint(10,10); //new運算返回對象的地址,并在動態(tài)內(nèi)存中創(chuàng)建了一個對象。48使用new運算符創(chuàng)建數(shù)組時,不能為該數(shù)組指定初值。執(zhí)行“CPoint
poCPoint=newCPoint(10,10);”語句時,得到了兩個東西:一個是對象指針變量,另一個是在動態(tài)內(nèi)存空間中的對象,而指針變量中的值,就是這個動態(tài)內(nèi)存空間中的對象的首地址,也就是動態(tài)內(nèi)存地址。而且這個對象是沒有名字的,只有通過指針進行訪問。492delete運算符delete釋放new所分配的存儲空間。<指針名>是存放了要釋放的存儲空間地址的指針變量名字。釋放new所創(chuàng)建數(shù)組時,使用“delete[]<指針名>;”的形式。delete只能用來釋放用new申請得的動態(tài)內(nèi)存空間,而且一次new只能夠對應一次delete。配對使用50deletepInt1;deletepInt2;delete[]pInt3;//釋放用new申請的數(shù)組空間//釋放由new申請的數(shù)組空間,對多維空間的釋放格式與一維空間相同。delete[]pInt4; deletepoCPoint;//釋放一個對象51注意:delete后,指針所指向的內(nèi)存空間就釋放了,但指針變量的值并沒有改變。指針還指向原來的內(nèi)存空間。所以,delete以后,應將指針變量的值設置成NULL,讓它不再指向原來的內(nèi)存空間,以免誤操作。例6_5:顯示了new和delete的基本使用smain6_5.cpp52
CPoint*poCPoint; //創(chuàng)建對象時,自動調(diào)用構造函數(shù)。
poCPoint=newCPoint[ARRAY_SIZE];//判斷動態(tài)內(nèi)存申請是否成功。
if(poCPoint==NULL) {
cout<<"動態(tài)內(nèi)存分配失敗。\n"; exit(0);//內(nèi)存申請失敗,則退出. }53
delete[]poCPoint; //釋放對象數(shù)組。
//動態(tài)內(nèi)存釋放后,讓poCPoint指針指向NULL。否則,它依然指向原動態(tài)空間。
poCPoint=NULL;
其內(nèi)容為垃圾54在例6_5中,數(shù)組中的5個對象其坐標都是(0,0,0)。這是由于給數(shù)組分配空間時,不能進行初始化(聲明時不能夠帶參數(shù))。也就是說:new一個對象數(shù)組時是不能夠帶參數(shù)的。缺省的參數(shù)則可以,構造函數(shù)缺省值為(0,0,0)。55對象數(shù)組的對象初始化有兩種方法:1、在類中不定義構造函數(shù),而定義一個成員函數(shù)專門用來完成初始化。2、在所定義的類中增加不帶參數(shù)或帶缺省參數(shù)的構造函數(shù)。動態(tài)數(shù)組初始化56"poCPoint=newCPoint[ARRAY_SIZE];“對應著: "delete[]poCPoint;";
而:"CTemp*poCTemp=newCTemp(5);” 對應著: "deletepoCTemp;"。如果new和delete形式不對應,結果將不可預測。573new和delete的重載new和delete可以在類內(nèi)重載,也可以在類外重載。類外重載就是全局函數(shù)重載,它會覆蓋系統(tǒng)預定義的new和delete功能,。類內(nèi):new和delete只能重載為成員函數(shù),不能重載為友元函數(shù)。而且,無論是否使用關鍵字static進行修飾,重載了的new和delete均為類的靜態(tài)成員函數(shù)。58void*operatornew(size_tsize){void*p=malloc(size);return(p);}voidoperatordelete(void*p);{free(p);}596.3.3常見的動態(tài)內(nèi)存錯誤編譯器不能自動發(fā)現(xiàn)動態(tài)內(nèi)存錯誤。在程序運行時才能捕捉到。常見的動態(tài)內(nèi)存錯誤有:1、使用未分配成功的動態(tài)內(nèi)存空間。在使用動態(tài)內(nèi)存之前必須檢查指針是否為NULL:函數(shù)入口處:assert(p!=NULL)
assert()函數(shù)對應的頭文件為:assert.h參考《C語言程序設計(C99)》,清華大學出版社申請時用:if(p==NULL)或if(p!=NULL)
進行檢查.602、使用未經(jīng)初始化的動態(tài)內(nèi)存空間。內(nèi)存的缺省初值可能是一個不確定的值
,所以,任何內(nèi)存空間的使用都應該立足于自己初始化。盡量不要使用系統(tǒng)缺省的初值。3、超過了內(nèi)存空間的邊界使用數(shù)組的操作也很容易越界;越界后就會操作到不正確的內(nèi)存單元.614、內(nèi)存泄露。是一種嚴重的內(nèi)存錯誤,極不容易發(fā)現(xiàn)。程序長期運行的話,最終會導致內(nèi)存耗盡。由于new和delete使用不配對new創(chuàng)建的動態(tài)空間,沒有用delete釋放等。5、使用已經(jīng)釋放了的內(nèi)存空間。用free或delete釋放內(nèi)存以后,指針變量p的值并沒有改變,它依然指向原來new的那一片內(nèi)存空間。釋放內(nèi)存以后,一定要將指針變量的值置成NULL。另外,在傳遞內(nèi)存指針時要避免傳遞棧內(nèi)存(存儲臨時變量的內(nèi)存)。626.3.4指針和數(shù)組的對比數(shù)組名對應著一塊內(nèi)存,其地址與容量在生命期內(nèi)保持不變,數(shù)組的內(nèi)容則可以改變;指針變量(尤其void*)則是一個變量,它可以存放任意的地址值,它可以隨時指向任意類型的內(nèi)存塊,所以指針遠比數(shù)組靈活、危險。例6_7說明了指針和數(shù)組在使用上的一些差異。使用不慎將引發(fā)內(nèi)存問題。smain6_7.cpp
63Oelloworldhellohello124646.3.5利用指針傳遞內(nèi)存的方式利用函數(shù)申請動態(tài)內(nèi)存,可以使用指向指針的指針、指針引用以及函數(shù)返回指針來傳遞動態(tài)內(nèi)存。例6_8:利用指向指針的指針、指針引用和函數(shù)返回指針傳遞內(nèi)存。smain6_8.cpp
hello,world.hello,china.hello,四川大學計算機學院!65例6_9:利用指針傳遞內(nèi)存時,注意不要傳遞棧內(nèi)存,否則指針會指向垃圾。smain6_9.cpp
棧內(nèi)存調(diào)用的結果為:,靜態(tài)內(nèi)存調(diào)用的結果為:helloworld在例6_9中:GetString1的return語句返回了指向“棧內(nèi)存”的指針,它是錯誤的,因為該內(nèi)存在函數(shù)結束時自動消失;而GetString2雖然返回了正確的結果,但它在設計概念上就已經(jīng)錯誤了(因得到的是常量空間)。66以下兩者本質上是不同的:charaChar[]="helloworld"; char*aChar="helloworld";動態(tài)數(shù)組初始化676.3.6delete的作用delete只是把指針所指向的內(nèi)存給釋放掉,它并沒有使指針本身消失。delete以后,指針還是指向其原來指向的內(nèi)存空間,指針變量的值并未改變。指針所指向的內(nèi)存空間的內(nèi)容已經(jīng)釋放掉了,其內(nèi)容變得毫無意義了,是垃圾,指針本身被懸掛了。此時用語句if(p!=NULL)進行防錯處理是毫無意義的.68在例6_10中,安排了這種懸掛所帶來的問題的示例程序。例6_10:delete對內(nèi)存干了什么?smain6_10.cpp
lpszChar和lpszChar2指向了同一片動態(tài)內(nèi)存空間,delete以后,內(nèi)存的內(nèi)容毫無意義,但是lpszChar和lpszChar2指針變量的值并沒有改變,還指向原來的位置。69lpszChar2:屯屯屯屯屯屯屯屯葺葺葺葺葺葺lpszChar:屯屯屯屯屯屯屯屯葺葺葺葺葺葺lpszChar2:hello,China!lpszChar:hello,China!lpszChar2:葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺lpszChar:葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺lpszChar2:helloworld。lpszChar:helloworld。70預防“指針懸掛”(指針所指向的內(nèi)存空間的內(nèi)容毫無意義了,是垃圾)和“野指針”(指針的變量是由系統(tǒng)自動生成的一個隨機值)從以下幾點入手:1、聲明指針時記住初始化,如不初始化就一定將其置成NULL.(否則產(chǎn)生野指針)2、指針delete以后,一定記得將其置為NULL。(否則產(chǎn)生指針懸掛)3、當指針指向數(shù)組時,謹防指針操作越界.(否則產(chǎn)生指針懸掛)4、避免指針指向一個已經(jīng)自動消失的局部變量。(否則產(chǎn)生指針懸掛)71voidFunc(void){ char*lpszChar=newchar[100]; }//在退出函數(shù)時,動態(tài)內(nèi)存會自動釋放嗎?72退出Func()的時候,lpszChar會自動消失;而動態(tài)內(nèi)存卻依然存在,沒有釋放,造成內(nèi)存泄漏。1、指針消亡了,并不表示它所指向的動態(tài)內(nèi)存會自動釋放了。2、動態(tài)內(nèi)存釋放了,并不表示指向該動態(tài)內(nèi)存的指針會消亡或自動變成NULL指針。736.4使用引用引用(&),就是給一個變量取別名。使用“引用”就是使用“被引用對象”本身它不需要建立臨時對象,傳遞效率較高。6.4.1引用類型intiA,iB;int&riA=iA;//int&riA=iB;//錯誤,引用是固定的。riA是iA的同義詞,它們表示同一個對象。74riA是iA的一個引用;iA是一般變量,它是被引用的對象。定義引用類型變量時必須初始化。引用只能引用一個固定的對象。初始化以后,引用關系就不可改變。對對象或對引用的任何操作都會影響到被引用對象本身。一個引用可看作一個特殊類型的指針。戀愛規(guī)則:從一而終751指針引用C中,改變指針本身——采用傳指針地址的方式.voidFunc(int
**ppInt);int
iNum=47;int*pInt=&iNum; //&表示取一般變量的地址Func(&pInt); //&表示取指針變量的地址76利用指針引用傳遞"指針值"。C++中,可以采用引用來完成。函數(shù)參數(shù)變成指針的引用,用不著取得指針的地址。voidNewMemory3(char*&lpszChar,int
iNum){
lpszChar=newchar[iNum]; if(NULL==lpszChar)
{
cout<<"內(nèi)存分配失敗"<<endl; exit(0); }}77voidTest3(void){ char*lpszStr=NULL;
NewMemory3(lpszStr,100);
strcpy(lpszStr,"hello,world.");
cout<<lpszStr<<endl; deletelpszStr;}傳遞動態(tài)內(nèi)存(用戶定義函數(shù))78
使用引用的限制使用引用時注意兩點:1、引用必須初始化。2、引用在初始化中被綁定到某個對象上后,將只能永遠綁定這個對象。不可空引用791、引用主要用于函數(shù)參數(shù)傳遞,解決大塊數(shù)據(jù)或對象的傳遞效率和空間效率問題。2、用引用傳遞函數(shù)參數(shù),不產(chǎn)生副本,提高傳遞效率,通過const的使用,保證了引用傳遞的安全性。電子匯兌郵局郵寄803、引用與指針的區(qū)別:指針通過某個指針變量指向一個對象后,對它所指向的變量間接操作。指針使程序可讀性差;而引用本身就是目標變量的別名,對引用的操作就是對目標變量的操作。引用固定,安全性高;指針可指向任何位置,危險。4、使用引用的時機:重載流操作符<<和>>的參數(shù)、賦值操作符=的返回值、拷貝構造函數(shù)的參數(shù)、賦值操作符=的參數(shù)、以及其它部分情況下都推薦使用引用。816.4.2獨立引用1、初始化時,賦值表達式的右端是一個變量。例如:int&riNum=iNum;iNum是一個變量。2、初始化時,賦值表達式的右端是一個常量值。例如(VC不允許對常量的引用)constdouble&rd2=1.0;實際上,相當于:constdoublerd2=1.0;82例6_11:引用變量和被引用變量的值同步變化.smain6_11.cpp
500600600500600600836.4.3引用作為函數(shù)參數(shù)值傳遞只能實現(xiàn)實參到形參的傳值,不能實現(xiàn)形參到實參的反向傳值。C++中,需要雙向傳值時,還可以采用引用。使用引用比使用指針傳值更安全,更方便,更直觀,更容易理解。例6_12:引用作為參數(shù),產(chǎn)生了雙向傳值的效果。smain6_12.cpp
84提高傳值的效率:
采用引用傳值,可以避免復制傳值過程,相應地提高了傳值的效率。引用就是實參對象本身,不需要復制。如果采用常引用,也不會改變實參,對實參來說也是安全的。例6_13:常引用作參數(shù),在不需要修改實參的時候,保證了所傳遞參數(shù)的安全性。而且傳遞效率高。smain6_13.cpp
856.4.4引用返回值函數(shù)返回引用,返回的是一個存儲單元(即變量)。因此,如果一個函數(shù)返回引用的話,則函數(shù)調(diào)用可以出現(xiàn)在賦值號的右邊。也可以出現(xiàn)在賦值號的左邊。例6_14:引用作為返回值。smain6_14.cpp
86函數(shù)返回引用作為左值使用的結果。在函數(shù)中未對數(shù)組元素作任何修改,但是數(shù)組元素值卻改變了。這是函數(shù)返回引用,并被作為左值操作的結果。
10010200102,4,6,8,10,12,14,16,18,20,2,4,6,8,10,12,100,16,18,20,876.4.5常引用常引用是用const修飾的引用,它常常用做形式參數(shù),用來限制對實參對象的修改。例如://參數(shù)是常引用,在函數(shù)中不可改變它。voidFunc(constCStudent&oCStudent); //不可通過riNum改變iNum的值。constint&riNum=iNum;
88例6_15:從源復制指定大小的字節(jié)數(shù)到目的。smain6_15.cpp
程序中,使用了“constvoid*pvFrom”作為形式參數(shù),這保證了實際參數(shù)lpszSource的安全性。同時也不會采用復制傳值,直接使用lpszSource,傳遞效率最高。896.5類型轉換類型轉換就是將一種類型轉換為另一種類型:標準類型之間可以相互轉換。類類型之間,標準類型和類類型之間也可以相互轉換。對于標準類型來說,C++提供了隱式類型轉換和顯示類型轉換兩種機制。而自定義類類型到基本類型的轉換則可由自己定義的構造函數(shù)和類型轉換函數(shù)來實現(xiàn)。906.5.1構造函數(shù)和類型轉換函數(shù)利用構造函數(shù)只能完成基本類型到類類型的轉換。從類類型到基本類型的轉換需要定義類型轉換函數(shù)。1基本類型轉化為類類型用構造函數(shù)進行類型轉換有一個前提,就是類中有一個只帶一個參數(shù)的構造函數(shù)。例6_16:實現(xiàn)由實型數(shù),字符串到CDouble類型的轉換。smain6_16.cpp91構造函數(shù)(1)完成從double型到CDouble類類型的轉換;構造函數(shù)(2)完成從char*到CDouble類類型的轉換,雖然它有2個參數(shù),但第2個參數(shù)缺省,所以它也可以只帶一個參數(shù)轉換。變臉92
類類型轉化為基本類型完成類類型到基本類型的轉換,可采用類類型轉換函數(shù)來實現(xiàn)。類類型轉換函數(shù)專門用來將類類型轉換為基本數(shù)據(jù)類型。
operator<基本類型名>(){ //…… return<基本類型值>;}無返回類型93沒有返回類型,<類型名>就代表了它的返回類型;沒有任何參數(shù)。在調(diào)用過程中要帶一個對象實參。類類型轉換函數(shù)沒有返回類型說明,但函數(shù)體必須有return語句,用于返回<基本類型值>。例6_17的"operatorint();"定義了一個類類型轉換為基本類型的例子。smain6_17.cpp94CInteger::operatorint(){ returnm_iNum;}定義類類型轉換函數(shù)時,應注意下列幾點:1、轉換函數(shù)是類的非靜態(tài)成員函數(shù)。2、轉換函數(shù)定義時,不進行返回值的類型說明,也沒有形參。956.5.2一個類型轉換實例例6_18:直角坐標到極(矢量)坐標的相互轉換。smain6_18.cpp
96X坐標為:2;Y坐標為:2X坐標為:0;Y坐標為:0極徑=4;極角=0.523333弧度。極徑=0;極角=0弧度。X坐標為:2;Y坐標為:2X坐標為:3.46463;Y坐標為:1.99908極徑=4;極角=0.523333弧度。極徑=2.82843;極角=0.785398弧度。976.6異常處理出錯處理即異常處理是提高程序健壯性的重要手段。異常主要指程序運行時異常。異常處理機制就是用于管理這種異常的一種方法。異常處理的基本結構throw、try和catch語句的一般語法如下:98throw<表達式>;try
{//try語句塊}catch(類型1參數(shù)1){//針對類型1的異常處理}catch(類型2參數(shù)2){//針對類型2的異常處理}//…catch(類型n參數(shù)n){//針對類型n的異常處理}1個參數(shù)99在設計catch程序時,catch出現(xiàn)的順序很重要。在一個try塊中引發(fā)異常時,異常處理程序按照它在catch中出現(xiàn)的順序進行檢查。catch的排列順序應從特殊到一般的排列順序(指異常對象從特殊到一般排列)。即應該將派生的異常捕獲放在前面,而將基類異常對象的捕獲放在處理程序后面。憲法和經(jīng)濟合同法1006.6.1C語言的出錯處理C語言的出錯處理方法,無法正確地清除對象。C++語言異常處理將異常的檢測與處理分開。C++異常處理機制采用結構化方法,就是:throw、try、catch結構。
1、throw:用來創(chuàng)建用戶自定義類型的異常錯誤,用于拋出異常。2、try:標識程序中異常語句塊,用于引發(fā)異常。3、catch:標識異常錯誤處理模塊,用于捕獲、處理異常。1016.6.2拋出異常throw<表達式>;
使用一般方式if(條件)
throw<表達式>異常規(guī)格申明(下個頁面還將詳細介紹)比如:voidExceptionFunction(argument)throw(ExceptionClass1,ExceptionClass2)表示函數(shù)ExceptionFunction中可拋出ExceptionClass1或ExceptionClass2類型的異常.如果某段程序發(fā)現(xiàn)了自己不能處理的異常,就可以使用throw表達式拋出這個異常,將它拋給調(diào)用者。102異常
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經(jīng)權益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 愛心流水燈課程設計
- 網(wǎng)球初學者教學課程設計
- 預見2025:中國行業(yè)趨勢報告-羅蘭貝格-202501
- 汽車行業(yè)品牌推廣咨詢
- 紡織服裝行業(yè)業(yè)務代表工作報告
- 教育行業(yè)人才選拔經(jīng)驗交流
- 2024年秋季小學開學典禮方案
- 2024年美發(fā)店管理制度
- 分布式電力供應合同(2篇)
- 2024年臘八節(jié)的賀詞
- 水閘閘門運行方案
- 消費型股東招募計劃書
- 2022-2023學年江蘇省連云港市九年級(上)期末數(shù)學試卷(含詳細答案解析)
- 會計事務所述職報告
- 2022年江蘇普通高中學業(yè)水平選擇性考試政治真題及答案
- 玻璃工業(yè)的節(jié)能減排與綠色制造
- 防止交叉感染的護理措施和策略
- 蘇教譯林版四年級英語上冊單詞默寫表
- 金屬冶煉中的領導潛能與領導力發(fā)展策略
- 上海市浦東新區(qū)部分學校聯(lián)考2023-2024學年七年級上學期期末考試數(shù)學試題
- 南京理工大學物理化學課程考試8套卷(含答案)
評論
0/150
提交評論