技術(shù)第13章cc編程_第1頁
技術(shù)第13章cc編程_第2頁
技術(shù)第13章cc編程_第3頁
技術(shù)第13章cc編程_第4頁
技術(shù)第13章cc編程_第5頁
已閱讀5頁,還剩81頁未讀, 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

第十三章C/C++編程規(guī)范MFC基礎(chǔ)教程

軟件質(zhì)量是被大多數(shù)程序員掛在嘴上而不是放在心上的東西。

試問有多少軟件開發(fā)人員對正確性、健壯性、可靠性、效率、易用性、可讀性(可理解性)、可擴展性、可復用性、兼容性、可移植性等質(zhì)量屬性了如指掌?1.文件結(jié)構(gòu)每個C/C++程序通常分為兩個文件:一個文件用于保存程序的聲明(declaration),稱為頭文件;另一個文件用于保存程序的實現(xiàn)(implementation),稱為定義(definition)文件。C/C++程序的頭文件以“.h”為后綴,C程序的定義文件以“.c”為后綴,C++程序的定義文件通常以“.cpp”為后綴。1.1版權(quán)和版本的聲明版權(quán)和版本的聲明位于頭文件和定義文件的開頭,主要內(nèi)容有:版權(quán)信息;文件名稱,標識符,摘要;當前版本號,作者/修改者,完成日期;版本歷史信息;/*Copyright?2011,武漢凡諾軟件有限公司Allrightsreserved.文件名稱:filename.h文件標識:見配置管理計劃書摘要:簡要描述本文件的內(nèi)容*當前版本:1.0作者:張三完成日期:2011年7月20日*/1.2頭文件的結(jié)構(gòu)頭文件由三部分內(nèi)容組成:頭文件開頭處的版權(quán)和版本聲明;預處理塊;函數(shù)和類結(jié)構(gòu)聲明等;規(guī)則為了防止頭文件被重復引用,應當用ifndef/define/endif結(jié)構(gòu)產(chǎn)生預處理塊。用#include<filename.h>格式來引用標準庫的頭文件。(編譯器將從標準庫目錄開始搜索)用#include”filename.h”格式來引用非標準庫的頭文件。(編譯器將從用戶的工作目錄開始搜索)建議頭文件中只存放“聲明”而不存放“定義”。在C++語法中,類的成員函數(shù)可以在聲明的同時被定義,并且自動成為內(nèi)聯(lián)函數(shù)。這不一致,弊大于利。建議將成員函數(shù)的雖然會帶來書寫上的方便,但卻造成了風格定義與聲明分開,不論該函數(shù)體有多么小。不提倡使用全局變量,盡量不要在頭文件中出現(xiàn)像externintvalue這類聲明。1.3定義文件的結(jié)構(gòu)定義文件有三部分內(nèi)容:定義文件開頭處的版權(quán)和版本聲明;對一些頭文件的引用;程序的實現(xiàn)體(包括數(shù)據(jù)和代碼);1.4目錄結(jié)構(gòu)如果一個軟件的頭文件數(shù)目比較多(如超過10個),通常應將頭文件和定義文件分別保存于不同的目錄,以便于維護。可將頭文件保存于include目錄,將定義文件保存于source目錄(可以是多級目錄)。如果某些頭文件是私有的,它不會被用戶的程序直接引用,則沒有必要公開其“聲明”。為了加強信息隱藏,這些私有的頭文件可以和定義文件存放于同一個目錄。2.程序的版式版式雖然不會影響程序的功能,但會影響可讀性。程序的版式追求清晰、美觀,是程序風格的重要構(gòu)成因素。2.1空行空行起著分隔程序段落的作用。空行得體(不過多也不過少)將使程序的布局更加清晰。規(guī)則在每個類聲明之后、每個函數(shù)定義結(jié)束之后都要加空行。在一個函數(shù)體內(nèi),邏輯上密切相關(guān)的語句之間不加空行,其它地方應加空行分隔。//函數(shù)之間的空行//空行voidFunction1(...){...}//空行voidFunction2(...){...}//空行voidFunction3(...){...}//函數(shù)內(nèi)部的空行while(condition){statement1;//空行if(condition){statement2;}else{statement3;}//空行statement4;}2.2代碼行代碼行是程序的實現(xiàn)體,也是整個程序的核心部分。代碼行的規(guī)范與否直接影響到軟件質(zhì)量的好壞。規(guī)則一行代碼只做一件事情,如只定義一個變量,或只寫一條語句。這樣的代碼容易閱讀,并且方便于寫注釋。If、for、while、do等語句自占一行,執(zhí)行語句不得緊跟其后。不論執(zhí)行語句有多少都要加{}。這樣可以防止書寫失誤。//風格良好的代碼行intwidth; //寬度intheight; //高度intdepth; //深度…x=a+b;y=c+d;…if(width<height){dosomething();}…for(initialization;condition;update){dosomething();}//空行other();//風格不良的代碼行intwidth,height,depth; //寬度…z=e+f;x=a+b;y=c+d;z=e+f;…if(width<height)dosomething();…for(initialization;condition;update)dosomething();other();建議盡可能在定義變量的同時初始化該變量(就近原則)。如果變量的引用處和其定義處相隔比較遠,變量的初始化很容易被忘記。如果引用了未被初始化的變量,可能會導致程序錯誤。2.3代碼行內(nèi)的空格代碼行內(nèi)的空格起著突出關(guān)鍵字、節(jié)段、優(yōu)先級等作用。規(guī)則關(guān)鍵字之后要留空格。像const、virtual、inline、case等關(guān)鍵字之后至少要留一個空格,否則無法辨析關(guān)鍵字。像if、for、while等關(guān)鍵字之后應留一個空格再跟左括號“(”,以突出關(guān)鍵字。函數(shù)名之后不要留空格,緊跟左括號“(”,以與關(guān)鍵字區(qū)別?!?”向后緊跟,“)”、“,”、“;”向前緊跟,緊跟處不留空格?!?”之后要留空格。如function(x,y,z)。如果“;”不是一行的結(jié)束符號,其后要留空格。如for(initialization;condition;update)。規(guī)則賦值操作符、比較操作符、算術(shù)操作符、邏輯操作符、位域操作符,如“=”、“+=”、“>=”、“<=”、“+”、“*”、“%”、“&&”、“||”、“<<”、“^”等二元操作符的前后應當加空格。一元操作符如“!”、“++”、“--”、“&”(地址運算符)等前后不加空格。象“[]”、“.”、“->”這類操作符前后不加空格。建議對于表達式比較長的for語句和if語句,為了緊湊起見可以適當?shù)厝サ粢恍┛崭?。如for(i=0;i<10;i++)如if((a<=b)&&(c<=d))//風格良好的代碼行voidFunc1(intx,inty,intz);…if(year>=2000)…if((a>=b)&&(c<=d))…for(i=0;i<10;i++)…x=a<b?a:b;…int*x=&y;…array[5]=0;a.Function();b->Function();//風格不良的代碼行voidFunc1(intx,inty,intz);…if(year>=2000)…if(a>=b&&c<=d)…for(i=0;i<10;i++)for(i=0;i<10;i++)//過多的空格…x=a<b?a:b;…int*x=&y;…array[5]=0; //錯誤a.Function(); //錯誤b->Function(); //錯誤2.4對齊通過代碼行的對齊能夠很直觀地查看到某行代碼所處的區(qū)域范圍,這樣便于程序調(diào)試。規(guī)則程序的分界符“{”和“}”應獨占一行并且位于同一列,同時與引用它們的語句左對齊。{}之內(nèi)的代碼塊在“{”右邊數(shù)格處左對齊。如果出現(xiàn)嵌套的{},則使用縮進對齊。//風格良好的代碼行voidFunc1(intx){…//programcode}…if(condition){…//programcode}else{…//programcode}…for(initialization;condition;update){…//programcode}//風格不良的代碼行voidFunc1(intx){…//programcode}…if(condition){…//programcode}else{…//prpgramcode}…for(initialization;condition;update){…//programcode}2.5長行拆分為了使代碼便于查看,需要對過長的代碼行進行拆分處理。規(guī)則代碼行最大長度宜控制在70至80個字符以內(nèi)。代碼行不要過長,否則眼睛看不過來,也不便于打印。長表達式要在低優(yōu)先級操作符處拆分成新行,操作符放在新行之首(以便于突出操作符)。拆分出的新行要進行適當?shù)目s進,使排版整齊,語句可讀。if((very_longer_variable1>=very_longer_variable12)&&(very_longer_variable3<=very_longer_variable14)&&(very_longer_variable5<=very_longer_variable16)){dosomething();}…virtualCmatrixCMultiplyMatrix(CMatrixleftMatrix, CmatrixrightMatrix);2.6修飾符的位置修飾符*和&應該靠近數(shù)據(jù)類型還是該靠近變量名,是個有爭議的話題。若將修飾符*靠近數(shù)據(jù)類型,例如:int*x;從語義上講此寫法比較直觀,即x是int類型的指針。上述寫法的弊端是容易引起誤解,例如:int*x,y;此處y容易被誤解為指針變量。雖然將x和y分行定義可以避免誤解,但并不是人人都愿意這樣做。規(guī)則應當將修飾符*和&緊靠變量名。例如:char*name;int*x,y; //此處y不會被誤解為指針2.7注釋C語言的注釋符為“/*…*/”。C++語言中,程序塊的注釋常采用“/*…*/”,行注釋一般采用“//…”。注釋通常用于:版本、版權(quán)聲明;函數(shù)接口說明;重要的代碼行或段落提示;雖然注釋有助于理解代碼,但注意不可過多地使用注釋。規(guī)則注釋是對代碼的“提示”,而不是文檔。程序中的注釋不可喧賓奪主,注釋太多了會讓人眼花繚亂,注釋的花樣要少。如果代碼本來就是清楚的,則不必加注釋。否則多此一舉,令人厭煩。例如:i++;//i加1,多余的注釋邊寫代碼邊注釋,修改代碼同時修改相應的注釋,以保證注釋與代碼的一致性。不再有用的注釋要刪除。注釋應當準確、易懂,防止注釋有二義性。錯誤的注釋不但無益反而有害。盡量避免在注釋中使用縮寫,特別是不常用縮寫。注釋的位置應與被描述的代碼相鄰,可以放在代碼的上方或右方,不可放在下方。當代碼比較長,特別是有多重嵌套時,應當在一些段落的結(jié)束處加注釋,便于閱讀。2.8類的版式類可以將數(shù)據(jù)和函數(shù)封裝在一起,其中函數(shù)表示了類的行為(或稱服務)。類提供關(guān)鍵字public、protected和private,分別用于聲明哪些數(shù)據(jù)和函數(shù)是公有的、受保護的或者是私有的。這樣可以達到信息隱藏的目的,即讓類僅僅公開必須要讓外界知道的內(nèi)容,而隱藏其它一切內(nèi)容。類的版式主要有兩種方式:將private類型的數(shù)據(jù)寫在前面,而將public類型的函數(shù)寫在后面。采用這種版式的程序員主張類的設(shè)計“以數(shù)據(jù)為中心”,重點關(guān)注類的內(nèi)部結(jié)構(gòu);將public類型的函數(shù)寫在前面,而將private類型的數(shù)據(jù)寫在后面。采用這種版式的程序員主張類的設(shè)計“以行為為中心”,重點關(guān)注的是類應該提供什么樣的接口(或服務);3.命名規(guī)則比較著名的命名規(guī)則當推Microsoft公司的“匈牙利”法,該命名規(guī)則的主要思想是“在變量和函數(shù)名中加入前綴以增進人們對程序的理解”。例如所有的字符變量均以ch為前綴,若是指針變量則追加前綴p。如果一個變量由ppch開頭,則表明它是指向字符指針的指針?!靶傺览狈ㄗ畲蟮娜秉c是繁瑣。沒有一種命名規(guī)則可以讓所有的程序員贊同,程序設(shè)計教科書一般都不指定命名規(guī)則。命名規(guī)則對軟件產(chǎn)品而言并不是“成敗攸關(guān)”的事。不必花太多精力試圖發(fā)明世界上最好的命名規(guī)則,而應當制定一種令大多數(shù)項目成員滿意的命名規(guī)則,并在項目中貫徹實施。3.1共性規(guī)則本節(jié)論述的共性規(guī)則是被大多數(shù)程序員采納的,我們應當在遵循這些共性規(guī)則的前提下,再擴充特定的規(guī)則。規(guī)則標識符應當直觀且可以拼讀,可望文之意,不必進行“解碼”。標識符最好采用英文單詞或其組合,便于記憶和閱讀。切忌使用漢語拼音來命名。程序中的英文單詞一般不會太復雜,用詞應當準確。標識符的長度應當符合“min-length&&max-information”原則。命名規(guī)則盡量與所采用的操作系統(tǒng)或開發(fā)工具的風格保持一致。程序中不要出現(xiàn)僅靠大小寫區(qū)分的相似的標識符。例如:intx,X; //變量x與X容易混淆voidfoo(intx); //函數(shù)foo與FOO容易混淆voidFOO(floatx);規(guī)則程序中不要出現(xiàn)標識符完全相同的局部變量和全局變量,盡管兩者的作用域不同而不會發(fā)生語法錯誤,但會使人誤解。變量的名字應當使用“名詞”或者“形容詞+名詞”。例如:floatvalue;floatoldValue;floatnewValue;全局函數(shù)的名字應當使用“動詞”或者“動詞+名詞”(動賓詞組)。類的成員函數(shù)應當只使用“動詞”,被省略掉的名詞就是對象本身。例如:DrawBox(); //全局函數(shù)box->Draw(); //類的成員函數(shù)用正確的反義詞組命名具有互斥意義的變量或相反動作的函數(shù)等。例如:intminValue;intmaxValue;intSetValue(…);intGetValue(…);建議盡量避免名字中出現(xiàn)數(shù)字編號,如Value1、Value2等,除非邏輯上的確需要編號。3.2簡單的Windows應用程序命名規(guī)則對“匈牙利”命名規(guī)則做了合理的簡化,下述的命名規(guī)則簡單易用,比較適合于Windows應用軟件的開發(fā)。規(guī)則類名和函數(shù)名用大寫字母開頭的單詞組合而成。例如:classNode; //類名classLeafNode; //類名voidDraw(void); //函數(shù)名voidSetValue(intvalue); //函數(shù)名變量和參數(shù)用小寫字母開頭的單詞組合而成。例如:BOOLflag;intdrawMode;常量全用大寫的字母,用下劃線分割單詞。例如:constintMAX=100;constintMAX_LENGTH=100;規(guī)則靜態(tài)變量加前綴s_(表示static)。例如:staticints_initValue; //靜態(tài)變量如果不得已需要全局變量,則使全局變量加前綴g_(表示global)。例如:intg_howManyPeople; //全局變量類的數(shù)據(jù)成員加前綴m_(表示member),這樣可以避免數(shù)據(jù)成員與成員函數(shù)的參數(shù)同名。例如:voidObject::SetValue(intwidth,intheight){m_width=width;m_height=height;}為了防止某一軟件庫中的一些標識符和其它軟件庫中的沖突,可以為各種標識符加上能反映軟件性質(zhì)的前綴。4.表達式和基本語句表達式和語句都屬于C/C++的短語結(jié)構(gòu)語法,它們看似簡單,但使用時隱患比較多。本節(jié)歸納了正確使用表達式和語句的一些規(guī)則與建議。4.1運算符的優(yōu)先級C/C++語言的運算符有數(shù)十個,運算符的優(yōu)先級與結(jié)合律表如下:運算符結(jié)合律()[]->.從左至右!~++--+-*(type)sizeof從右至左*/%從左至右+-從左至右<<>>從左至右<<=>>=從左至右==!=從左至右&從左至右^從左至右|從左至右&&從左至右||從左至右?:從右至左=+=-=*=/=%=&=^=|=<<=>>=從右至左,從左至右規(guī)則如果代碼行中的運算符比較多,用括號確定表達式的操作順序,避免使用默認的優(yōu)先級。由于將優(yōu)先級結(jié)合律表熟記時比較困難的,為了防止產(chǎn)生歧義并提高可讀性,應當用括號確定表達式的操作順序。例如:word=(high<<8)|lowif((a|b)&&(a&c))4.2復合表達式如a=b=c=0這樣的表達式稱為復合表達式。允許復合表達式存在的理由是:書寫簡潔;可以提高編譯效率。但要防止濫用復合表達式;規(guī)則不要編寫太復雜的復合表達式。例如:i=a>=b&&c<d&&c+f<=g_h; //復合表達式過于復雜不要有多用途的復合表達式。例如:d=(a=b+c)+r;//既求a值又求d值,應拆分為兩個獨立的語句。a=b+c;d=a+r;不要把程序中的復合表達式與“真正的數(shù)學表達式”混淆。例如:if(a<b<c) //a<b<c是數(shù)學表達式而不是程序表達式并不表示if((a<b)&&(b<c))而是成了令人費解的if((a<b)<c)4.3if語句if語句是C/C++語言中最簡單、最常用的語句,然而很多程序員用隱含錯誤的方式寫if語句。規(guī)則布爾變量與零值比較,不可將布爾變量直接與TRUE、FALSE或者1、0進行比較。假設(shè)布爾變量名字為flag,它與零值比較的標準if語句如下:if(flag) //表示flag為真if(!flag) //表示flag為假整型變量與零值比較,應當將整型變量用“==”或“!=”直接與0比較。假設(shè)整型變量的名字為value,它與零值比較的標準if語句如下:if(value==0)if(value!=0)規(guī)則浮點變量與零值比較,不可將浮點變量用“==”或“!=”與任何數(shù)字比較。千萬要留意,無論是float還是double類型的變量,都有精度限制。所以應該設(shè)法轉(zhuǎn)化成“>=”或“<=”形式。假設(shè)浮點變量的名字為x,應當將if(x==0.0)//隱含錯誤的比較轉(zhuǎn)化為if((x>=-EPSINON)&&(x<=EPSINON))//EPSINON是允許的誤差(精度)指針變量與零值比較,應當將指針變量用“==”或“!=”與NULL比較。指針變量的零值是“空”(NULL)。盡管NULL的值與0相同,但是兩者意義不同。假設(shè)指針變量的名字為p,它與零值比較的標準if語句如下:if(p==NULL) //p與NULL顯式比較,強調(diào)p是指針變量if(p!=NULL)建議有時候我們可能會看到if(NULL==p)這樣古怪的格式。不是程序?qū)戝e了,是程序員為了防止將if(p==NULL)誤寫成if(p=NULL),而有意把p和NULL顛倒。編譯器認為if(p=NULL)是合法的,但是會指出if(NULL=p)是錯誤的,因為NULL不能被賦值。程序中有時會遇到if/else/return的組合,應該作如下處理:if(condition)returnx;returny;//改寫為:if(condition){returnx;}else{returny;}4.4循環(huán)語句的效率C/C++循環(huán)語句中,for語句使用頻率最高,while語句其次,do語句很少用。本節(jié)重點論述循環(huán)體的效率。提高循環(huán)體效率的基本辦法是降低循環(huán)體的復雜性。建議在多重循環(huán)中,如果有可能,應當將最長的循環(huán)放在最內(nèi)層,最短的循環(huán)放在最外層,以減少CPU跨切循環(huán)層的次數(shù)。//低效率:長循環(huán)在最外層for(row=0;row<100;row++){for(col=0;col<5;col++){sum=sum+a[row][col];}}//高效率:長循環(huán)在最內(nèi)層for(col=0;col<5;col++){for(row=0;row<100;row++){sum=sum+a[row][col];}}建議如果循環(huán)體內(nèi)存在邏輯判斷,并且循環(huán)次數(shù)很大,宜將邏輯判斷移到循環(huán)體的外面。示例A比示例B多執(zhí)行力N-1次邏輯判斷,并且由于前者老要進行邏輯判斷,打斷了循環(huán)“流水線”作業(yè),使得編譯器不能對循環(huán)進行優(yōu)化處理,降低了效率。如果N非常大,最好采用示例B的寫法,可以提高效率。如果N非常小,兩者效率差別不明顯,采用示例A的寫法比較好,因為程序更加簡潔。//示例A,效率低但程序簡潔for(i=0;i<N;i++){if(condition)DoSomething();elseDoOtherthing();}//示例B,效率高但程序不簡潔if(condition){for(i=0;i<N;i++)DoSomething();}else{for(i=0;i<N;i++)DoOtherthing();}4.5for語句的循環(huán)控制變量在for語句中,循環(huán)控制變量直接影響for內(nèi)代碼的執(zhí)行次數(shù)。規(guī)則不可在for循環(huán)體內(nèi)修改循環(huán)變量,防止for循環(huán)失去控制。建議建議for語句的循環(huán)控制變量的取值采用“半開半閉區(qū)間”寫法。示例A中的x值屬于半開半閉區(qū)間“0=<x<N”,起點到終點的間隔為N,循環(huán)次數(shù)為N。示例B中的x值屬于閉區(qū)間“0=<x<=N-1”,起點到終點的間隔為N-1,循環(huán)次數(shù)為N。相比之下,示例A的寫法更加直觀,盡管兩者的功能是相同的。//示例A,循環(huán)變量屬于半開半閉區(qū)間for(intx=0;x<N;x++){...}//示例B,循環(huán)變量屬于閉區(qū)間for(intx=0;x<=N-1;x++){...}4.6switch語句有了if語句為什么還要switch語句?switch是多分支選擇語句,而if語句只有兩個分支可供選擇。雖然可以用嵌套的if語句來實現(xiàn)多分支選擇,但那樣的程序冗長難讀。這是switch語句存在的理由。switch語句的基本格式是:switch(variable){casevalue1:...break;casevalue2:...break;default:...break;}規(guī)則每個case語句的結(jié)尾不要忘了加break,否則將導致多個分支重疊(除非有意使多個分支重疊)。不要忘記最后那個default分支。即使程序真的不需要default處理,也應該保留該語句,這樣做并非多此一舉,而是為了防止別人誤以為你忘了default處理。4.7goto語句自從提倡結(jié)構(gòu)化設(shè)計以來,goto就成了有爭議的語句。首先,goto語句可以靈活跳轉(zhuǎn),如果不加限制,它的確會破壞結(jié)構(gòu)化設(shè)計風格。其次,goto語句經(jīng)常帶來錯誤或隱患。它可能跳過了某些對象的構(gòu)造、變量的初始化、重要的計算等語句,如果編譯器不能發(fā)覺此類錯誤,每用一次goto語句都可能留下隱患。很多人建議廢除C/C++的goto語句,以絕后患。但實事求是地說,錯誤是程序員自己造成的,不是goto的過錯。goto語句至少有一處可顯神通,它能從多重循環(huán)體中一下子跳到外面,用不著寫很多次的break語句。我們主張少用、慎用goto語句,而不是禁用。5.常量常量是一種標識符,它的值在運行期間恒定不變。C語言用#define來定義常量(稱為宏常量),C++語言除了#define外還可以用const來定義常量(稱為const常量)。5.1為什么需要常量如果不使用常量,直接在程序中填寫數(shù)字或字符串,將會有以下麻煩:程序的可讀性(可理解性)變差。程序員自己會忘記那些數(shù)字或字符串是什么意思,用戶則更加不知它們從何處來、表示什么;在程序的很多地方輸入同樣的數(shù)字或字符串,難保不發(fā)生書寫錯誤;如果要修改數(shù)字或字符串,則會在很多地方改動,既麻煩又容易出錯;規(guī)則盡量使用含義直觀的常量來表示那些將在程序中多次出現(xiàn)的數(shù)字或字符串。例如:#define MAX 100 /*C語言的宏常量*/constint MAX=100; //C++語言的const常量constfloatPI=3.14159; //C++語言的const常量5.2const與#define的比較C++語言可以用const來定義常量,也可以用#define來定義常量。但是前者比后者有更多的優(yōu)點:const常量有數(shù)據(jù)類型,而宏常量沒有數(shù)據(jù)類型。編譯器可以對前者進行類型安全檢查。而對后者只進行字符替換,沒有類型安全檢查,并且在字符替換可能會產(chǎn)生意料不到的錯誤(邊際效應);有些集成化的調(diào)試工具可以對const常量進行調(diào)試,但是不能對宏常量進行調(diào)試;規(guī)則在C++程序中只使用const常量而不使用宏常量,即const常量完全取代宏常量。需要對外公開的常量放在頭文件中,不需要對外公開的常量放在定義文件的頭部。為便于管理,可以把不同模塊的常量集中存放在一個公共的頭文件中。如果某一常量與其它常量密切相關(guān),應在定義中包含這種關(guān)系,而不應給出一些孤立的值。例如:constfloatRADIUS=100;constfloatDIAMETER=RADIUS*2;5.3類中的常量有時我們希望某些常量只在類中有效。由于#define定義的宏常量是全局的,不能達到目的,于是想當然地覺得應該用const修飾數(shù)據(jù)成員來實現(xiàn)。const數(shù)據(jù)成員的確是存在的,但其含義卻不是我們所期望的。const數(shù)據(jù)成員只在某個對象生存期內(nèi)是常量,而對于整個類而言卻是可變的,因為類可以創(chuàng)建多個對象,不同的對象其const數(shù)據(jù)成員的值可以不同。不能在類聲明中初始化const數(shù)據(jù)成員,const數(shù)據(jù)成員的初始化只能在類構(gòu)造函數(shù)的初始化表中進行。若要建立在整個類中都恒定的常量,就不能用const數(shù)據(jù)成員了,應該用類中的枚舉常量來實現(xiàn)。枚舉常量不會占用對象的存儲空間,它們在編譯時被全部求值。枚舉常量的缺點是:它的隱含數(shù)據(jù)類型是整數(shù),其最大值有限,且不能表示浮點數(shù)。6.函數(shù)設(shè)計函數(shù)是C/C++程序的基本功能單元,其重要性不言而喻。函數(shù)設(shè)計的細微缺點很容易導致該函數(shù)被錯用,所以光使函數(shù)的功能正確是不夠的。函數(shù)接口的兩個要素是參數(shù)和返回值。C語言中,函數(shù)的參數(shù)和返回值的傳遞方式有兩種:值傳遞(passbyvalue)和指針傳遞(passbypointer)。C++語言中多了引用傳遞(passbyreference)。6.1參數(shù)的規(guī)則好的函數(shù)的參數(shù)規(guī)范,能夠讓調(diào)用者無需查看接口文檔便能大概知道如何傳入?yún)?shù),大大方便了接口調(diào)用人員。規(guī)則參數(shù)的書寫要完整,不要貪圖省事只寫參數(shù)的類型而省略參數(shù)名字。如果函數(shù)沒有參數(shù),則用void填充。//良好的風格voidSetValue(intwidth,intheight);floatGetValue(void);//不良的風格voidSetValue(int,int);floatGetValue();參數(shù)命名要恰當,順序要合理。例如編寫字符串拷貝函數(shù)StringCopy(char*str1,char*str2),我們很難搞清楚究竟是把str1拷貝到str2中,還是剛好倒過來。把參數(shù)名字起得有意義,如strSource和strDestination,這樣就不會產(chǎn)生誤解。參數(shù)的順序要遵循程序員的習慣。一般地,應將目的參數(shù)放在前面,源參數(shù)放在后面。規(guī)則如果參數(shù)是指針,且僅作輸入用,則應在類型前加const,以防止該指針在函數(shù)體內(nèi)被意外修改。如果輸入?yún)?shù)以值傳遞的方式傳遞對象,則宜改用“const&”方式來傳遞,這樣可以省去臨時對象的構(gòu)造和析構(gòu)過程,從而提高效率。建議避免函數(shù)有太多的參數(shù),參數(shù)個數(shù)盡量控制在5個以內(nèi)。如果參數(shù)太多,在使用時容易將參數(shù)類型或順序搞錯。盡量不要使用類型和數(shù)目不確定的參數(shù)。C標準庫函數(shù)printf是采用不確定參數(shù)的典型代表,其原型為:intprintf(constchar*format[,argument]...);這種風格的函數(shù)在編譯時喪失了嚴格的類型安全檢查。6.2返回值的規(guī)則返回值是函數(shù)功能實現(xiàn)的結(jié)果,也是需要按照一定規(guī)范來編寫的。規(guī)則不要省略返回值的類型。C語言中,凡不加類型說明的函數(shù),一律自動按整型處理。這樣做不會有什么好處,卻容易被誤解為void類型。C++語言有很嚴格的類型安全檢查,不允許上述情況發(fā)生。由于C++程序可以調(diào)用C函數(shù),為了避免混亂,規(guī)定任何C/C++函數(shù)都必須有類型。如果函數(shù)沒有返回值,那么應聲明為void類型。函數(shù)名字與返回值類型在語義上不可沖突。不要將正常值和錯誤標志混在一起返回。正常值用輸出參數(shù)獲得,而錯誤標志用return語句返回。建議有時候函數(shù)原本不需要返回值,但為了增加靈活性如支持鏈式表達,可以附加返回值。例如字符串拷貝函數(shù):char*strcpy(char*strDest,constchar*strSrc);strcpy函數(shù)將strSrc拷貝至輸出參數(shù)strDest中,同時函數(shù)的返回值又是strDest。這樣做并非多此一舉,可以獲得如下靈活性:intlength=strlen(strcpy(str,“HelloWorld”));如果函數(shù)的返回值是一個對象,有些場合用“引用傳遞”替換“值傳遞”可以提高效率。而有些場合只能用“值傳遞”而不能用“引用傳遞”,否則會出錯。6.3函數(shù)內(nèi)部實現(xiàn)的規(guī)則不同功能的函數(shù)其內(nèi)部實現(xiàn)各不相同,看起來似乎無法就“內(nèi)部實現(xiàn)”達成一致的觀點。但根據(jù)經(jīng)驗,我們可以在函數(shù)體的“入口處”和“出口處”從嚴把關(guān),從而提高函數(shù)的質(zhì)量。規(guī)則在函數(shù)體的“入口處”,對參數(shù)的有效性進行檢查。很多程序錯誤是由非法參數(shù)引起的,我們應該充分理解并正確使用“斷言”(assert)來防止此類錯誤。在函數(shù)體的“出口處”,對return語句的正確性和效率進行檢查。如果函數(shù)有返回值,那么函數(shù)的“出口處”是return語句。我們不要輕視return語句,如果return語句寫得不好,函數(shù)要么出錯,要么效率低下。注意事項如下:return語句不可返回指向“棧內(nèi)存”的“指針”或者“引用”,因為該內(nèi)存在函數(shù)體結(jié)束時被自動銷毀;要搞清楚返回的究竟是“值”、“指針”還是“引用”;如果函數(shù)返回值是一個對象,要考慮return語句的效率;建議函數(shù)的功能要單一,不要設(shè)計多用途的函數(shù)。函數(shù)體的規(guī)模要小,盡量控制在50行代碼之內(nèi)。盡量避免函數(shù)帶有“記憶”功能。相同的輸入應當產(chǎn)生相同的輸出。帶有“記憶”功能的函數(shù),其行為可能是不可預測的,因為它的行為可能取決于某種“記憶狀態(tài)”。這樣的函數(shù)既不以理解又不利于測試和維護。在C/C++語言中,函數(shù)的static局部變量是函數(shù)的“記憶”存儲器。建議少用static局部變量,除非必需。不僅要檢查輸入?yún)?shù)的有效性,還要檢查通過其它途徑進入函數(shù)體內(nèi)的變量的有效性,例如全局變量、文件句柄等。用于出錯處理的返回值一定要清楚,讓使用者不容易忽視或誤解錯誤情況。7.內(nèi)存管理內(nèi)存管理是C++最令人切齒痛恨的問題,也是C++最有爭議的問題,內(nèi)存泄漏幾乎在每個C++程序中都會發(fā)生。7.1內(nèi)存分配方式內(nèi)存分配方式有三種:從靜態(tài)存儲區(qū)域分配。內(nèi)存在程序編譯的時候就已經(jīng)分配好,這塊內(nèi)存在程序的整個運行期間都存在。例如全局變量,static變量;在棧上創(chuàng)建。在執(zhí)行函數(shù)時,函數(shù)內(nèi)局部變量的存儲單元都可以在棧上創(chuàng)建,函數(shù)執(zhí)行結(jié)束時這些存儲單元自動被釋放。棧內(nèi)存分配運算內(nèi)置于處理器的指令集中,效率很高,但是分配的內(nèi)存容量有限;從堆上分配,亦稱動態(tài)內(nèi)存分配。程序在運行的時候用malloc或new申請任意多少的內(nèi)存,程序員自己負責在何時用free或delete釋放內(nèi)存。動態(tài)內(nèi)存的生存期由我們決定,使用非常靈活,但問題也最多;規(guī)則用malloc或new申請內(nèi)存之后,應該立即檢查指針值是否為NULL。防止使用指針值為NULL的內(nèi)存。不要忘記為數(shù)組和動態(tài)內(nèi)存賦初值。防止將未被初始化的內(nèi)存作為右值使用。避免數(shù)組或指針的下標越界,特別要當心發(fā)生“多1”或者“少1”操作。動態(tài)內(nèi)存的申請與釋放必須配對,防止內(nèi)存泄漏。用free或delete釋放了內(nèi)存之后,立即將指針設(shè)置為NULL,防止產(chǎn)生“野指針”。8.類的繼承與組合對象(Object)是類(Class)的一個實例(Instance)。如果將對象比作房子,那么類就是房子的設(shè)計圖紙。所以面向?qū)ο笤O(shè)計的重點是類的設(shè)計,而不是對象的設(shè)計。對于C++程序而言,設(shè)計孤立的類是比較容易的,難的是正確設(shè)計基類及其派生類。本節(jié)僅僅論述“繼承”(Inheritance)和“組合”(Composition)的概念。8.1繼承如果A是基類,B是A的派生類,那么B將繼承A的數(shù)據(jù)和函數(shù)。classA{public:voidFunc1(void);voidFunc2(void);};classB:publicA{public:voidFunc3(void);voidFunc4(void);};main(){Bb;b.Func1();//B從A繼承了函數(shù)Func1b.Func2();//B從A繼承了函數(shù)Func2b.Func3();b.Func4();}C++的“繼承”特性可以提高程序的可復用性。正因為“繼承”太有用、太容易用,才要防止亂用“繼承”。規(guī)則如果類A

溫馨提示

  • 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. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論