




版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
推薦-高質量C++/C編程指南(林銳)
版木/狀態(tài)作者參與者起止日期備注
V0.9林銳2001-7-1至林銳起草
草稿文件2001-7-18
V1.0林銳2001-7-18至朱洪海審查V0.9,
正式文件2001-7-24林銳修正草稿中的錯誤
目錄
前言…6
第1章文件結構…11
1.1版權和版本的聲明…11
1.2頭文件的結構…12
1.3定義文件的結構…13
1.4頭文件的作用…13
1.5目錄結構…14
第2章程序的版式…15
2.1空行…15
2.2代碼行…16
2.3代碼行內的空格…17
2.4對齊…18
2.5長行拆分…19
2.6修飾符的位置…19
2.7注釋…20
2.8類的版式…21
第3章命名規(guī)則…22
3.1共性規(guī)則…22
3.2簡單的Windows應用程序命名規(guī)則…23
3.3簡單的Unix應用程序命名規(guī)則…25
第4章表達式和基本語句…26
4.1運算符的優(yōu)先級…26
4.2復合表達式…27
4.3if語句…27
4.4循環(huán)語句的效率…29
4.5for語句的循環(huán)控制變量…30
4.6switch語句…30
4.7goto語句…31
第5章常量…33
5.1為什么需要常量…33
5.2const與#define的比較...33
5.3常量定義規(guī)則…33
5.4類中的常量…34
第6章函數(shù)設計…36
6.1參數(shù)的規(guī)則…36
6.2返回值的規(guī)則...37
6.3函數(shù)內部實現(xiàn)的規(guī)則…39
6.4其它建議…40
6.5使用斷言…41
6.6引用與指針的比較...42
第7章內存管理…44
7.1內存分配方式…44
7.2常見的內存錯誤及其對策…44
7.3指針與數(shù)組的對比…45
7.4指針參數(shù)是如何傳遞內存的?…47
7.5free和delete把指針怎么啦?...50
7.6動態(tài)內存會被自動釋放嗎?…50
7.7杜絕“野指針”…51
7.8有了malloc/free為什么還要new/delete?...52
7.9內存耗盡怎么辦?…53
7.10malloc/free的使用要點...54
7.11new/delete的使用要點…55
7.12一些心得體會…56
第8章C++函數(shù)的高級特性…57
8.1函數(shù)重載的概念…57
8.2成員函數(shù)的重載、覆蓋與隱藏…60
8.3參數(shù)的缺省值…63
8.4運算符重載…64
8.5函數(shù)內聯(lián)…65
8.6一些心得體會…68
第9章類的構造函數(shù)、析構函數(shù)與賦值函數(shù)…69
9.1構造函數(shù)與析構函數(shù)的起源…69
9.2構造函數(shù)的初始化表…70
9.3構造和析構的次序…72
9.4示例:類String的構造函數(shù)與析構函數(shù)…72
9.5不要輕視拷貝構造函數(shù)與賦值函數(shù)…73
9.6示例:類String的拷貝構造函數(shù)與賦值函數(shù)…73
9.7偷懶的辦法處理拷貝構造函數(shù)與賦值函數(shù)…75
9.8如何在派生類中實現(xiàn)類的基本函數(shù)…75
9.9一些心得體會…77
第10章類的繼承與組合…78
10.1繼承…78
10.2組合…80
第11章其它編程經(jīng)驗…82
11.1使用const提高函數(shù)的健壯性…82
11.2提高程序的效率…84
11.3?些有益的建議…85
參考文獻…87
附錄A:C++/C代碼審查表…88
附錄B:C++/CK?...93
附錄C:C++/C試題的答案與評分標準…97
、八、A
刖5
軟件質量是被大多數(shù)程序員掛在嘴上而不是放在心上的東西!
除了完全外行和真正的編程高手外,初讀本書,你最先的感受將是驚慌:“哇!我以前捏造的
C++/C程序怎么會有那么多的毛???”
別難過,作者只不過比你早幾年、多幾次驚慌而已。
請花一兩個小時認真閱讀這本百頁經(jīng)書,你將會獲益匪淺,這是前面N-1個讀者的建議。
一、編程老手與高手的誤區(qū)
自從計算機問世以來,程序設計就成了令人羨慕的職業(yè),程序員在受人寵愛之后容易發(fā)展成為毛
病特多卻常能自我臭美的群體。
如今在Internet上流傳的“真正”的程序員據(jù)說是這樣的:
(1)真正的程序員沒有進度表,只有討好領導的馬屁精才有進度表,真正的程序員會讓領導
提心吊膽。
(2)真正的程序員不寫使用說明書,用戶應當自己去猜想程序的功能。
(3)真正的程序員幾乎不寫代碼的注釋,如果注釋很難寫,它理所當然也很難讀。
(4)真正的程序員不畫流程圖,原始人和文盲才會干這事。
(5)真正的程序員不看參考手冊,新手和膽小鬼才會看。
(6)真正的程序員不寫文檔也不需要文檔,只有看不懂程序的笨蛋才用文檔。
(7)真正的程序員認為自己比用戶更明白用戶需要什么。
(8)真正的程序員不接受團隊開發(fā)的理念,除非他自己是頭頭。
(9)真正的程序員的程序不會在第一次就正確運行,但是他們愿意守著機器進行若干個30小
時的調試改錯。
(10)真正的程序員不會在上午9:00到下午5:00之間工作,如果你看到他在上午9:00工作,
這表明他從昨晚一直干到現(xiàn)在。
具備上述特征越多,越顯得水平高,資格老。所以別奇怪,程序員的很多缺點竟然可以被當作優(yōu)
點來欣賞。就象在武俠小說中,那些獨來獨往、不受約束且?guī)c邪氣的高手最令人崇拜。我曾經(jīng)
也這樣信奉,并且希望自己成為那樣的“真正”的程序員,結果沒有得到好下場。
我從讀大學到博士畢業(yè)十年來一直勤奮好學,累計編寫了數(shù)十萬行C++/C代碼。有這樣的苦勞
和疲勞,我應該稱得上是編程老手了吧?
我開發(fā)的軟件都與科研相關(集成電路CAD和3D圖形學領域),動輒數(shù)萬行程序,技術復雜,
難度頗高。這些軟件頻頻獲獎,有一個軟件獲得首屆中國大學生電腦大賽軟件展示一等獎。在
1995年開發(fā)的一套圖形軟件庫到2000年還有人買。羅列出這些“業(yè)績”,可以說明我算得上是
編程高手了吧?
可惜這種個人感覺不等于事實。
讀博期間我曾用一年時間開發(fā)了?個近10萬行C++代碼的3D圖形軟件產(chǎn)品,我內心得意表
面謙虛地向一位真正的軟件高手請教。他雖然從未涉足過3D圖形領域,卻在幾十分鐘內指出該
軟件多處重大設計錯誤。讓人感覺那套軟件是用紙糊的華麗衣服,扯一下掉塊,戳一下破個洞。
我目瞪口呆地意識到這套軟件毫無實用價值,一年的心血白化了,并且害死了自己的軟件公司。
人的頓悟通常發(fā)生在最心痛的時刻,在沮喪和心痛之后,我作了深刻反省,“面壁”半年,重新溫
習軟件設計的基礎知識。補修“內功”之后,乂覺得腰板硬了起來。博士畢業(yè)前半年,我曾到微軟
中國研究院找工作,接受微軟公司一位資深軟件工程師的面試。他讓我寫函數(shù)strcpy的代碼。
太容易了吧?
錯!
這么一個小不點的函數(shù),他從三個方面考查:
(1)編程風格;
(2)出錯處理;
(3)算法復雜度分析(用于提高性能)。
在大學里從來沒有人如此嚴格地考查過我的程序。我化了半個小時,修改了數(shù)次,他還不盡滿意,
讓我回家好好琢磨。我精神抖擻地進“考場”,大汗淋漓地出“考場”。這“高手”當?shù)靡蔡C囊了。
我又好好地反省了一次。
我把反省后的心得體會寫成文章放在網(wǎng)上傳閱,引起了不少軟件開發(fā)人員的共鳴。我因此有幸和
國產(chǎn)大型IT企業(yè)如華為、上海貝爾、中興等公司的同志們廣泛交流。大家認為提高質量與生產(chǎn)
率是軟件工程要解決的核心問題。高質量程序設計是非常重要的環(huán)節(jié),畢竟軟件是靠編程來實現(xiàn)
的。
我們心目中的老手們和高手們能否編寫出高質量的程序來?
不見得都能!
就我的經(jīng)歷與閱歷來看,國內大學的計算機教育壓根就沒有灌輸高質量程序設計的觀念,教師們
和學生們也很少自覺關心軟件的質量。勤奮好學的程序員長期在低質量的程序堆中滾爬,吃盡苦
頭之后才有一些心得體會,長進極慢,我就是一例。
現(xiàn)在國內IT企業(yè)擁有學士、碩士、博士文憑的軟件開發(fā)人員比比皆是,但他們在接受大學教育
時就“先天不足”,豈能一到企業(yè)就突然實現(xiàn)質的飛躍。試問有多少軟件開發(fā)人員對正確性、健壯
性、可靠性、效率、易用性、可讀性(可理解性)、可擴展性、可復用性、兼容性、可移植性等
質量屬性了如指掌?并且能在實踐中運用自如??!案哔|量”可不是干活小心點就能實現(xiàn)的!
我們有充分的理由疑慮:
(1)編程老手可能會長期用隱含錯誤的方式編程(習慣成自然),發(fā)現(xiàn)毛病后都不愿相信那是
真的!
(2)編程高手可以在某一領域寫出極有水平的代碼,但未必能從全局把握軟件質量的方方面面。
事實證明如此。我到上海貝爾工作一年來,陸續(xù)面試或測試過近百名“新”“老”程序員的編
程技能,質量合格率大約是10%。很少有人能夠寫出完全符合質量要求的if語句,很多程序員
對指針、內存管理一知半解......
領導們不敢相信這是真的。我做過現(xiàn)場試驗:有一次部門新進14名碩士生,在開歡迎會之前對
他們進行“C++/C編程技能”摸底考試。我問大家試題難不難?所有的人都回答不難。結果沒有
一個人及格,有半數(shù)人得零分。競爭對手公司的朋友們也做過試驗,同樣?敗涂地。
真的不是我“心狠手辣”或者要求過高,而是很多軟件開發(fā)人員對自己的要求不夠高。
要知道華為、上海貝爾、中興等公司的員工素質在國內IT企業(yè)中是比較前列的,倘若他們的編
程質量都如此差的話,我們怎么敢期望中小公司拿出高質量的軟件呢?連程序都編不好,還談什
么振興民族軟件產(chǎn)業(yè),豈不胡扯。
我打算定義編程老手和編程高手,請您別見笑。
定義1:能長期穩(wěn)定地編寫出高質量程序的程序員稱為編程老手。
定義2:能長期穩(wěn)定地編寫出高難度、高質量程序的程序員稱為編程高手。
根據(jù)上述定義,馬上得到第推論:我既不是高手也算不上是老手。
在寫此書前,我閱讀了不少程序設計方面的英文著作,越看越羞慚。因為發(fā)現(xiàn)自己連編程基本技
能都未能全面掌握,頂多算是二流水平,還好意思談什么老手和高手。希望和我一樣在國內土生
土長的程序員朋友們能夠做到:
(1)知錯就改;
(2)經(jīng)常溫故而知新;
(3)堅持學習,天天向上。
二、本書導讀
首先請做附錄B的C++/C試題(不要看答案),考查自己的編程質量究竟如何。然后參照
答案嚴格打分。
(1)如果你只得了幾十分,請不要聲張,也不要太難過。編程質量差往往是由于不良習慣造成
的,與人的智力、能力沒有多大關系,還是有藥可救的。成績越差,可以進步的空間就越大,中
國不就是在落后中趕超發(fā)達資本主義國家嗎?只要你能卜決心改掉不良的編程習慣,第二次考試
就能及格了。
(2)如果你考及格了,表明你的技術基礎不錯,希望你能虛心學習、不斷進步。如果你還沒有
找到合適的工作單位,不妨到上海貝爾試?試。
(3)如果你考出85分以上的好成績,你有義務和資格為你所在的團隊作“C++/C編程”培訓。
希望你能和我們多多交流、相互促進。半年前我曾經(jīng)發(fā)現(xiàn)一顆好苗子,就把他挖到我們小組來。
(4)如果你在沒有任何提示的情況下考了滿分,希望你能收我做你的徒弟。
編程考試結束后,請閱讀本書的iE文。
木書第一章至第六章主要論述C++/C編程風格。難度不高,但是細節(jié)比較多。別小看了,
提高質量就是要從這些點點滴滴做起。世上不存在最好的編程風格,?切因需求而定。團隊開發(fā)
講究風格一致,如果制定了大家認可的編程風格,那么所有組員都要遵守。如果讀者覺得本書的
編程風格比較合你的工作,那么就采用它,不要只看不做。人在小時候說話發(fā)音不準,寫字潦草,
如果不改正,總有后悔的時候。編程也是同樣道理。
第七章至第十一章是專題論述,技術難度比較高,看書時要積極思考。特別是第七章“內存管
理”,讀了并不表示懂了,懂了并不表示就能正確使用。有一位同事看了第七章后覺得“野指針”
寫得不錯,與我切磋了--把。可是過了兩周,他告訴我,他忙了兩天追查出一?個Bug,想不到
又是“野指針”出問題,只好重讀第七章。
光看本書對提高編程質量是有限的,建議大家閱讀本書的參考文獻,那些都是經(jīng)典名著。
如果你的編程質量已經(jīng)過關了,不要就此滿足。如果你想成為優(yōu)秀的軟件開發(fā)人員,建議
你閱讀并按照CMMI規(guī)范做事,讓自己的綜合水平上升一個臺階。上海貝爾的員工可以向網(wǎng)絡
應用事業(yè)部軟件工程研究小組索取CMMI有關資料,最好能參加培訓。
三、版權聲明
本書的大部分內容取材于作者一年前的書籍手稿(尚未出版),現(xiàn)整理匯編成為上海貝爾
網(wǎng)絡應用事業(yè)部的一個規(guī)范化文件,同時作為培訓教材。
由于C++/C編程是眾所周知的技術,沒有秘密可言。編程的好經(jīng)驗應該大家共享,我們
自己也是這么學來的。作者愿意公開本書的也子文檔。
版權聲明如下:
(1)讀者可以任意拷貝、修改本書的內容,但不可以篡改作者及所屬單位。
(2)未經(jīng)作者許可,不得出版或大量印發(fā)本書。
(3)如果競爭對手公司的員工得到本書,請勿公開使用,以免發(fā)生糾紛。
預計到2002年7月,我們將建立切合中國國情的CMMI3級解決方案。屆時,包括本
書在內的約1000頁規(guī)范將嚴格受控。
歡迎讀者對本書提出批評建議。
林銳,2001年7月
第1章文件結構
每個C++/C程序通常分為兩個文件。一個文件用于保存程序的聲明(declaration),稱為頭
文件。另一個文件用于保存程序的實現(xiàn)(implementation),稱為定義(definition)文件。
C++/C程序的頭文件以“.h”為后綴,C程序的定義文件以“.c”為后綴,C++程序的定義文件通
常以“.cpp”為后綴(也有一些系統(tǒng)以“?CC”或“.CXX”為后綴)。
1.1版權和版本的聲明
版權和版本的聲明位于頭文件和定義文件的開頭(參見示例1-1),主要內容有:
(1)版權信息。
(2)文件名稱,標識符,摘要。
(3)當前版本號,作者/修改者,完成口期。
(4)版本歷史信息。
*Copyright(c)2001,上海貝爾有限公司網(wǎng)絡應用事業(yè)部
*Allrightsreserved.
*
*文件名稱:filename.h
*文件■標識:見配置管理計劃書
*摘要:簡要描述本文件的內容
*
*當前版本:1.1
*作為:輸入作者(或修改者)名字
*完成日期:2001年7月20日
*
*取代版本:1.0
*原作者:輸入原作者(或修改者)名字
*完成日期:2001年5月日
示例1-1版權和版本的聲明
1.2頭文件的結構
頭文件由三部分內容組成:
(1)頭文件開頭處的版權和版本聲明(參見示例1-1)。
(2)預處理塊。
(3)函數(shù)和類結構聲明等。
假設頭文件名稱為graphics.h,頭文件的結構參見示例1-2。
I【規(guī)則1-2-1】為了防止頭文件被重復引用,應當用ifndef/define/endif結構產(chǎn)生預
處理塊。
I【規(guī)則1-2-2】用#include〈filename.h>格式來引用標準庫的頭文件(編譯器將
從標準庫目錄開始搜索)。
I【規(guī)則1-2-3】用#include"filename.h"格式來引用非標準庫的頭文件(編譯器將
從用戶的工作目錄開始搜索)。
2【建議1-2-1】頭文件中只存放“聲明”而不存放“定義”
在C++語法中,類的成員函數(shù)可以在聲明的同時被定義,并且自動成為內聯(lián)函數(shù)。這雖然會
帶來書寫上的方便,但卻造成了風格不一致,弊大于利。建議將成員函數(shù)的定義與聲明分開,不
論該函數(shù)體有多么小。
2【建議1-2-2]不提倡使用全局變量,盡量不要在頭文件中出現(xiàn)象externintvalue這
類聲明。
II版權和版本聲明見示例此處省略。
#ifndefGRAPHICS_H〃防止graphics.h被重復引用
#defineGRAPHICS_H
#include<math.h>//引用標準庫的頭文件
#includeumyheader.hn//引用非標準庫的頭文件
voidFunctionl(...);//全局函數(shù)聲明
classBox//類結構聲明
);
#endif
示例1-2C++/C頭文件的結構
1.3定義文件的結構
定義文件有三部分內容:
(1)定義文件開頭處的版權和版本聲明(參見示例1-1)。
(2)對一些頭文件的引用。
(3)程序的實現(xiàn)體(包括數(shù)據(jù)和代碼)。
假設定義文件的名稱為graphics.cpp,定義文件的結構參見示例1-3。
//版權和版本聲明見示例1-1,此處省略。
#include"graphics.h"http://引用頭文件
//全局函數(shù)的實現(xiàn)體
voidFunctionl(...)
)
//類成員函數(shù)的實現(xiàn)體
voidBox::Draw(...)
}
示例1-3C++/C定義文件的結構
1.4頭文件的作用
早期的編程語言如Basic、Fortran沒有頭文件的概念,C++/C語言的初學者雖然會用使用頭
文件,但常常不明其理。這里對頭文件的作用略作解釋:
(1)通過頭文件來調用庫功能。在很多場合,源代碼不便(或不準)向用戶公布,只要向用戶
提供頭文件和二進制的庫即可。用戶只需要按照頭文件中的接口聲明來調用庫功能,而不必關心
接口怎么實現(xiàn)的。編譯器會從庫中提取相應的代碼。
(2)頭文件能加強類型安全檢查。如果某個接口被實現(xiàn)或被使用時,其方式與頭文件中的聲明
不一致,編譯器就會指出錯誤,這?簡單的規(guī)則能大大減輕程序員調試、改錯的負擔。
1.5目錄結構
如果一個軟件的頭文件數(shù)目比較多(如超過十個),通常應將頭文件和定義文件分別保存于不同
的目錄,以便于維護。
例如可將頭文件保存于include目錄,將定義文件保存于source目錄(可以是多級目錄)。
如果某些頭文件是私有的,它不會被用戶的程序直接引用,則沒有必要公開其“聲明”。為了加強
信息隱藏,這些私有的頭文件可以和定義文件存放于同一個目錄。
第2章程序的版式
版式雖然不會影響程序的功能,但會影響可讀性。程序的版式追求清晰、美觀,是程序風
格的重要構成因素。
可以把程序的版式比喻為“書法”。好的“書法”可讓人對程序一目了然,看得興致勃勃。差的程序
“書法”如螃蟹爬行,讓人看得索然無味,更令維護者煩惱有加。請程序員們學習程序的“書法”,
彌補大學計算機教育的漏洞,實在很有必要。
2.1空行
空行起著分隔程序段落的作用。空行得體(不過多也不過少)將使程序的布局更加清晰??招胁?/p>
會浪費內存,雖然打印含有空行的程序是會多消耗一些紙張,但是值得。所以不要舍不得用空行。
I【規(guī)則2-1-1]在每個類聲明之后、每個函數(shù)定義結束之后都要加空行。參見示例2-1
(a)
I【規(guī)則2-1-2]在一個函數(shù)體內,邏揖上密切相關的語句之間不加空行,其它地方應加
空行分隔。參見示例2-1(b)
//空行//空行
voidFunctionl(...)while(condition)
((
statementl;
)//空行
//空行if(condition)
voidFunction2(...)(
(statement2;
)
)else
II空行(
voidFunction3(...)statements;
()
//空行
)statement4;
)
示例2-1(a)函數(shù)之間的空行示例2-1(b)函數(shù)內部的空行
2.2代碼行
I【規(guī)則2-2-1]一行代碼只做一件事情,如只定義一個變量,或只寫一條語句。這樣的
代碼容易閱讀,并且方便于寫注釋。
I【規(guī)則2-2-2】if、for、while,d。等語句自占一行,執(zhí)行語句不得緊跟其后。不論
執(zhí)行語句有多少都要加{}。這樣可以防止書寫失誤。
示例2-2(a)為風格良好的代碼行,示例2-2(b)為風格不良的代碼行。
intwidth;//寬度intwidth,height,depth;//寬度高度深度
intheight;//高度
intdepth;//深度
x=a+b;X=a+b;y=c+d;z=e+f;
y=c+d;
z=e+f;
if(width<height)if(width<height)dosomething();
(
dosomething();
)
for(initialization;condition;update)for(initialization;condition;update)
(dosomething();
dosomething();other();
)
//空行
other();
示例2-2(a)風格良好的代碼行示例2-2(b)風格不良的代碼行
21建議2-2-1]盡可能在定義變量的同時初始化該變量(就近原則)
如果變量的引用處和其定義處相隔比較遠,變量的初始化很容易被忘記。如果引用了未被初始化
的變量,可能會導致程序錯誤。本建議可以減少隱患。例如
intwidth=10;//定義并初紿化width
intheight=10;//定義并初紿化height
intdepth=10;//定義并初紿化depth
2.3代碼行內的空格
I【規(guī)則2-3-1】關鍵字之后要留空格。象const、virtual,inline,case等關鍵字之
后至少要留一個空格,否則無法辨析關鍵字。象if、for,while等關鍵字之后應留一個空格再
跟左括號‘(',以突出關鍵字。
I【規(guī)則2-3-2】函數(shù)名之后不要留空格,緊跟左括號‘(',以與關鍵字區(qū)別。
I【規(guī)則2-3-31’(響后緊跟,‘)向前緊跟,緊跟處不留空格。
I【規(guī)則2-3-4],,’之后要留空格,如Function。,y,z)。如果不是一行的結束符
號,其后要留空格,如for(initialization;condition;update)?
I【規(guī)則2-3-5]賦值操作符、比較操作符、算術操作符、邏輯操作符、位域操作符,如
等二元操作符的前后應
當加空格。
I【規(guī)則2-3-6】一元操作符如“一”、“&”(地址運算符)等前后不加
空格。
I【規(guī)則2-3-7】象“口這類操作符前后不加空格。
21建議2-3-1】對于表達式比較長的for語句和if語句,為了緊湊起見可以適當?shù)厝サ?/p>
一些空格,如for(i=0;i<10;i++)和if((a<=b)&&(c<=d))
voidFund(intx,inty,intz);//良好的風格
voidFund(intx,inty,intz);//不良的風格
if(year>=2000)//良好的風格
if(year>=2000)//不良的風格
if((a>=b)&&(c<=d))//良好的風格
if(a>=b&&c<=d)//不良的風格
for(i=0;i<10;i++)//良好的風格
for(i=0;i<10;i++)//不良的風格
for(i=0;I<10;i++)//過多的空格
x=a<b?a:b;//良好的風格
x=a<b?a:b;//不好的風格
int*x=&y;//良好的風格
int*x=&y;//不良的風格
array[5]=0;//不要寫成array[5]=0;
a.Function();//不要寫成a.Function();
b->Function();//不要寫成b->Function();
示例2-3代碼行內的空格
2.4對齊
I【規(guī)則2-4-1]程序的分界符'{'和'}'應獨占一行并且位于同一列,同時與引用它們的
語句左對齊。
I【規(guī)則2-4-2]{}之內的代碼塊在丁右邊數(shù)格處左對齊。
示例2-4(a)為風格良好的對齊,示例2-4(b)為風格不良的對齊。
voidFunction(intx)voidFunction(intx){
(...IIprogramcode
...//programcode}
)
if(condition)if(condition)(
(...//programcode
...IIprogramcode}
)else{
else...IIprogramcode
(}
...IIprogramcode
)
for(initialization;condition;update)for(initialization;condition;update){
(...IIprogramcode
…〃programcode)
)
While(condition)while(condition){
(...IIprogramcode
...IIprogramcode)
)
如果出現(xiàn)嵌套的{},則使用縮進對齊,如:
(
(
)
)
示例2-4(a)風格良好的對齊示例2-4(b)風格不良的對齊
2.5長行拆分
I【規(guī)則2-5-1】代碼行最大長度宜控制在70至80個字符以內。代碼行不要過長,否
則眼睛看不過來,也不便于打印。
I【規(guī)則2-5-2]長表達式要在低優(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);
for(very_longer_initialization;
very_longer_condition;
very_longer_update)
(
dosomething();
示例2-5長行的拆分
2.6修飾符的位置
修飾符*和&應該靠近數(shù)據(jù)類型還是該靠近變量名,是個有爭議的活題。
若將修飾符*靠近數(shù)據(jù)類型,例如:int*x;從語義上講此寫法比較直觀,即x是int類型的
指針。
上述寫法的弊端是容易引起誤解,例如:int*x,y;此處y容易被誤解為指針變量。雖然將x
和y分行定義可以避免誤解,但并不是人人都愿意這樣做。
I【規(guī)則2-6-1】應當將修飾符*和&緊靠變量名
例如:
char*name;
int*x,y;〃此處y不會被誤解為指針
2.7注釋
C語言的注釋符為"/*…*/”。C++語言中,程序塊的注釋常采用行注釋一般采用
,7/...%注釋通常用于:
(1)版本、版權聲明;
(2)函數(shù)接口說明;
(3)重要的代碼行或段落提示。
雖然注釋有助于理解代碼,但注意不可過多地使用注釋。參見示例2-6。
I【規(guī)則2-7-1]注釋是對代碼的“提示”,而不是文檔。程序中的注釋不可喧賓奪主,注
釋太多了會讓人眼花繚亂。注釋的花樣要少。
I【規(guī)則2-7-2】如果代碼本來就是清楚的,則不必加注釋。否則多此一舉,令人厭煩。
例如
i++;〃i力口1,多余的注釋
I【規(guī)則2-7-3】邊寫代碼邊注釋,修改代碼同時修改相應的注釋,以保證注釋與代碼的
一致性。不再有用的注釋要刪除。
I【規(guī)則2-7-4]注釋應當準確、易懂,防止注釋有二義性。錯誤的注釋不但無益反而有
害。
I【規(guī)則2-7-5]盡量避免在注釋中使用縮寫,特別是不常用縮寫。
I【規(guī)則2-7-6]注釋的位置應與被描述的代碼相鄰,可以放在代碼的上方或右方,不可
放在下方。
I【規(guī)則2-7-8】當代碼比較長,特別是有多重嵌套時,應當在一些段落的結束處加注釋,
便于閱讀。
/*if(...)
*函數(shù)介紹:(
*輸入?yún)?shù):
*輸出參數(shù):while(...)
*返回值:(
*/
voidFunction(floatx,floaty,floatz)}//endofwhile
(
}//endofif
)
示例2-6程序的注釋
2.8類的版式
類可以將數(shù)據(jù)和函數(shù)封裝在一起,其中函數(shù)表示了類的行為(或稱服務)。類提供關鍵字public,
protected和private,分別用于聲明哪些數(shù)據(jù)和函數(shù)是公有的、受保護的或者是私有的。這樣
可以達到信息隱藏的目的,即讓類僅僅公開必須要讓外界知道的內容,而隱藏其它一切內容。我
們不可以濫用類的封裝功能,不要把它當成火鍋,什么東西都往里扔。
類的版式主要有兩種方式:
(1)將private類型的數(shù)據(jù)寫在前面,而將public類型的函數(shù)寫在后面,如示例8-3(a)。
采用這種版式的程序員主張類的設計“以數(shù)據(jù)為中心”,重點關注類的內部結構。
(2)將public類型的函數(shù)寫在前面,而符private類型的數(shù)據(jù)寫在后面,如示例8.3(b)采
用這種版式的程序員主張類的設計“以行為為中心”,重點關注的是類應該提供什么樣的接口(或
服務)。
很多C++教課書受到BiarneStroustrup第一本著作的影響,不知不覺地采用了“以數(shù)據(jù)為中
心,,的書寫方式,并不見得有多少道理。
我建議讀者采用“以行為為中心”的書寫方式,即首先考慮類應該提供什么樣的函數(shù)。這是很多人
的經(jīng)驗——“這樣做不僅讓自己在設計類時思路清晰,而且方便別人閱讀。因為用戶最關心的是
接口,誰愿意先看到一堆私有數(shù)據(jù)成員!”
classAclassA
((
private:public:
inti,j;voidFund(void);
floatx,y;voidFunc2(void);
public:private:
voidFund(void);inti,j;
voidFunc2(void);floatx,y;
))
示例8.3(a)以數(shù)據(jù)為中心版式示例8.3(b)以行為為中心的版式
第3章命名規(guī)則
比較著名的命名規(guī)則當推Microsoft公司的“匈牙利”法,該命名規(guī)則的主要思想是“在變量和函
數(shù)名中加入前綴以增進人們對程序的理解”。例如所有的字符變量均以ch為前綴,若是指針變
量則追加前綴P。如果?個變量由ppch開頭,則表明它是指向字符指針的指針。
“匈牙利”法最大的缺點是煩瑣,例如
inti,j,k;
floatx,y,z;
倘若采用“匈牙利”命名規(guī)則,則應當寫成
intil,iJ,ik;〃前綴i表示int類型
floatfX,fY,fZ;//前綴f表示float類型
如此煩瑣的程序會讓絕大多數(shù)程序員無法忍受。
據(jù)考察,沒有?種命名規(guī)則可以讓所有的程序員贊同,程序設計教科書?般都不指定命名規(guī)則。
命名規(guī)則對軟件產(chǎn)品而言并不是“成敗悠關”的事,我們不要化太多精力試圖發(fā)明世界上最好的命
名規(guī)則,而應當制定一種令大多數(shù)項目成員滿意的命名規(guī)則,并在項目中貫徹實施。
3.1共性規(guī)則
本節(jié)論述的共性規(guī)則是被大多數(shù)程序員采納的,我們應當在遵循這些共性規(guī)則的前提下,
再擴充特定的規(guī)則,如3.2節(jié)。
I【規(guī)則3-1-1】標識符應當直觀且可以拼讀,可望文知意,不必進行“解碼”。
標識符最好采用英文單詞或其組合,便于記憶和閱讀。切忌使用漢語拼音來命名。程序中的英文
單詞般不會太復雜,用詞應當準確。例如不要把Currentvalue寫成NowValue.
I【規(guī)則3-1-2】標識符的長度應當符合"min-length&&max-information"原則。
兒十年前老ANSIC規(guī)定名字不準超過6個字符,現(xiàn)今的C++/C不再有此限制。一般來說,
長名字能更好地表達含義,所以函數(shù)名、變量名、類名長達十幾個字符不足為怪。那么名字是否
越長約好?不見得!例如變量名maxval就比maxValuellntilOverflow好用。單字符的名字
也是有用的,常見的如i,j,k,m,n,x,y,z等,它們通常可用作函數(shù)內的局部變量。
I【規(guī)則3-1-3]命名規(guī)則盡量與所采用的操作系統(tǒng)或開發(fā)工具的風格保持一致。
例如Windows應用程序的標識符通常采用"大小寫”混排的方式,如AddChild。而Unix應用
程序的標識符通常采用“小寫加下劃線”的方式,如add_childo別把這兩類風格混在一起用。
I【規(guī)則3-1-4】程序中不要出現(xiàn)僅靠大小寫區(qū)分的相似的標識符。
例如:
intx,X;〃變量x與X容易混淆
voidfoo(intx);//函數(shù)foo與F0。容易混淆
voidFOO(floatx);
I【規(guī)則3-1-5]程序中不要出現(xiàn)標識符完全相同的局部變量和全局變量,盡管兩者的作
用域不同而不會發(fā)生語法錯誤,但會使人誤解。
【規(guī)貝IJ3-1-6]變量的名字應當使用“名詞”或者“形容詞+名詞屋
例如:
floatvalue;
floatoldValue;
floatnewValue;
I【規(guī)貝I」3-1-7]全局函數(shù)的名字應當使用“動詞”或者“動詞+名詞”(動賓詞組)。類的
成員函數(shù)應當只使用“動詞”,被省略掉的名詞就是對象本身。
例如:
DrawBox();//全局函數(shù)
box->Draw();//類的成員函數(shù)
I【規(guī)則3-1-8]用正確的反義詞組命名具有互斥意義的變量或相反動作的函數(shù)等。
例如:
intminValue;
intmaxValue;
intSetValue(...);
intGetValue(...);
2【建議3-1-1]盡量避免名字中出現(xiàn)數(shù)字編號,如Value1,Value2等,除非邏輯上的
確需要編號。這是為了防止程序員偷懶,不肯為命名動腦筋而導致產(chǎn)生無意義的名字(因為用數(shù)
字編號最省事)。
3.2簡單的Windows應用程序命名規(guī)則
作者對“匈牙利”命名規(guī)則做了合理的簡化,下述的命名規(guī)則簡單易用,比較適合于
Windows應用軟件的開發(fā)。
I【規(guī)則3-2-1]類名和函數(shù)名用大寫字母開頭的單詞組合而成。
例如:
classNode;//類名
classLeafNode;//類名
voidDraw(void);//函數(shù)名
voidSetValue(intvalue);//函數(shù)名
I【規(guī)則3-2-2]變量和參數(shù)用小寫字母開頭的單詞組合而成。
例如:
BOOLflag;
intdrawMode;
I【規(guī)則3-2-3】常量全用大寫的字母,用下劃線分割單詞。
例如:
constintMAX=100;
constintMAX_LENGTH=100;
I【規(guī)則3-2-4]靜態(tài)變量加前綴s_(表示static)。
例如:
voidlnit(...)
(
staticints_initValue;//靜態(tài)變量
I【規(guī)則3-2-5]如果不得己需要全局變量,則使全局變量加前綴g_(表示global)。
例如:
intg_howManyPeople;//全局變量
intg_howMuchMoney;//全局變量
I【規(guī)則3-2-6】類的數(shù)據(jù)成員加前綴m_(表示member),這樣可以避免數(shù)據(jù)成員
與成員函數(shù)的參數(shù)同名。
例如:
voidObject::SetValue(intwidth,intheight)
(
m_width=width;
m_height=height;
)
I【規(guī)則3-2-7]為了防止某一軟件庫中的一些標識符和其它軟件庫中的沖突,可以為各
種標識符加上能反映軟件性質的前綴。例如三維圖形標準。penGL的所有庫函數(shù)均以gl開頭,
所有常量(或宏定義)均以GL開頭。
3.3簡單的Unix應用程序命名規(guī)則
第4章表達式和基本語句
讀者可能懷疑:連if、for、while,goto、switch這樣簡單的東西也要探討編程風格,是不是
小題大做?
我真的發(fā)覺很多程序員用隱含錯誤的方式寫表達式和基本語句,我自己也犯過類似的錯誤。
表達式和語句都屬于C++/C的短語結構語法。它們看似簡單,但使用時隱患比較多。本章歸納
了正確使用表達式和語句的一些規(guī)則與建議。
4.1運算符的優(yōu)先級
C++/C語言的運算符有數(shù)十個,運算符的優(yōu)先級與結合律如表4-1所示。注意一元運算
符+-*的優(yōu)先級高于對應的二元運算符。
優(yōu)先級運算符結合律
()[]->.從左至右
!~++--(類型)sizeof從右至左
從
+-*&
*/%從左至右
高
+-從左至右
到<<>>從左至右
<<=>>=從左至右
低
==!=從左至右
排&從左至右
A從左至右
列
I從左至右
&&從左至右
II從右至左
?:從右至左
=+=-=*=/=%=&=A=從左至右
I=<<=>>=
表4-1運算符的優(yōu)先級與結合律
I【規(guī)則4-1-1】如果代碼行中的運算符比較多,用括號確定表達式的操作順序,避免使
用默認的優(yōu)先級。
由于將表4-1熟記是比較困難的,為了防止產(chǎn)生歧義并提高可讀性,應當用括號確定表達式的
操作順序。例如:
word=(high<<8)|low
if((a|b)&&(a&c))
4.2復合表達式
如a=b=c=O這樣的表達式稱為復合表達式。允許復合表達式存在的理由是:(1)書寫
簡潔;(2)可以提高編譯效率。但要防止濫用復合表達式。
I【規(guī)則4-2-1】不要編寫太復雜的復合表達式。
例如:
i=a>=b&&c<d&&c+f<=g+h;//復合表達式過于復雜
I【規(guī)則4-2-2]不要有多用途的復合表達式。
例如:
d=(a=b+c)+r;
該表達式既求a值又求d值。應該拆分為兩個獨立的語句:
a=b+c;
d=a+r;
I【規(guī)則4-2-3】不要把程序中的復合表達式與“真正的數(shù)學表達式”混淆。
例如:
if(a<b<c)〃a<b<c是數(shù)學表達式而不是程序表達式
并不表示
if((a<b)&&(b<c))
而是成了令人費解的
if((a<b)<c)
4.3if語句
if語句是C++/C語言中最簡單、最常用的語句,然而很多程序員用隱含錯誤的方式寫if語
句。本節(jié)以“與零值比較”為例,展開討論。
4.3.1布爾變量與零值比較
I【規(guī)貝。4-3-1]不可將布爾變量直接與TRUE、FALSE或者1、0進行比較。
根據(jù)布爾類型的語義,零值為“假”(記為FALSE),任何非零值都是“真"(記為TRUE).TRUE
的值究竟是什么并沒有統(tǒng)一的標準。例如VisualC++將TRUE定義為1,而VisualBasic
則將TRUE定義為-1。
假設布爾變量名字為flag,它與零值比較的標準if語句如下:
if(flag)〃表示flag為真
if((flag)//表示flag為假
其它的用法都屬于不良風格,例如:
if(flag==TRUE)
if(flag==1)
if(flag==FALSE)
if(flag==0)
4.3.2整型變量與零值比較
I【規(guī)則4-3-2】應當將整型變量用“=="或“!=”直接與0比較。
假設整型變量的名字為value,它與零值比較的標準if語句如下:
if(value==0)
if(value!=0)
不可模仿布爾變量的風格而寫成
if(value)//會讓人誤解value是布爾變量
if(lvalue)
4.3.3浮點變量與零值比較
I【規(guī)則4-3-3]不可將浮點變量用“=="或"!=”與任何數(shù)字比較。
千萬要留意,無論是float還是double類型的變量,都有精度限制。所以一定要避免將浮
點變量用“=="或"!=”與數(shù)字比較,應該設法轉化成“>="或“<=”形式。
假設浮點變量的名字為x,應當將
if(x==0.0)//隱含錯誤的比較
轉化為
if((x>=-EPSINON)&&(x<=EPSINON))
其中EPSINON是允許的誤差(即精度)。
4.3.4指針變量與零值比較
I【規(guī)則4-3-4】應當將指針變量用“=="或"!=”與NULL比較。
指針變量的零值是“空”(記為NULL)。盡管NULL的值與0相同,但是兩者意義不同。假
設指針變量的名字為P,它與零值比較的標準if語句如下:
if(p==NULL)〃p與NULL顯式比較,強調p是指針變量
if(p!=NULL)
不要寫成
if(p==0)//容易讓人誤解p是整型變量
if(p!=0)
或者
if(p)〃容易讓人誤解p是布爾變量
if(!p)
4.3.5對if語句的補充說明
有時候我們可能會看到if(NULL==p)這樣古怪的格式。不是程序寫錯了,是程序員為了防
止將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;
)
或者改寫成更加簡練的
return(condition?x:y);
4.4循環(huán)語句的效率
C++/C循環(huán)語句中,for語句使用頻率最高,while語句其次,do語句很少用。本節(jié)重點
論述循環(huán)體的效率。提高循環(huán)體效率的基本辦法是降低循環(huán)體的復雜性。
I【建議4-4-1】在多重循環(huán)中,如果有可能,應當將最長的循環(huán)放在最內層,最短的循
環(huán)放在最外層,以減少CPU跨切循環(huán)層的次數(shù)。例如示例4-4(b)的效率比示例4-4(a)的高。
for(row=0;row<100;row++)for(col=0;col<5;col++)
((
for(col=0;col<5;col++)for(row=0;row<100;row++)
((
sum=sum+a[row][col];sum=sum+a[row][col];
))
)
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經(jīng)權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025年云南省建水縣高三質量監(jiān)測(三)物理試題試卷含解析
- 周口職業(yè)技術學院《生物工程設備與設計》2023-2024學年第二學期期末試卷
- 上海歐華職業(yè)技術學院《幼兒園一日活動設計與組織》2023-2024學年第二學期期末試卷
- 臨夏現(xiàn)代職業(yè)學院《小學教育科學研究方法》2023-2024學年第二學期期末試卷
- 山東省東營市2024-2025學年六年級數(shù)學小升初摸底考試含解析
- 公車加油卡管理使用制度
- 汕尾排水帶施工方案
- 內蒙古赤峰市名校2024-2025學年高一上學期期末聯(lián)考英語試題(含聽力)
- 安徽省智學大聯(lián)考2024-2025學年高二上學期1月期末英語試題【含答案】
- 沈陽彩色混凝土施工方案
- 2025年全國高考體育單招政治時事填空練習50題(含答案)
- 2024年醫(yī)療器械經(jīng)營質量管理規(guī)范培訓課件
- 中華人民共和國學前教育法-知識培訓
- 2024年計算機二級WPS考試題庫380題(含答案)
- 節(jié)能評估報告編制要求 具體規(guī)定
- 基于智能巡檢機器人與PLC系統(tǒng)聯(lián)動控制設計和實現(xiàn)電子信息工程專業(yè)
- 畢業(yè)設計(論文)VFP小說租閱管理系統(tǒng)
- 河南省內影響工程選址的主要活動斷裂資料匯編(最終版)
- (完整版)幼兒園教師優(yōu)質課評分表
- 河北省工傷職工停工留薪期分類目錄 (工傷)
- 人民調解檔案規(guī)范文本.doc調解文書的格式及使用說明
評論
0/150
提交評論