1 前言
本編碼規範針對C++語言。制定本規範的目的:
提高代碼的健壯性,使代碼更安全、可靠;
提高代碼的可讀性,使代碼易於查看和維護。
本文檔分別對C++程序的格式、註釋、標識符命名、語句使用、函數、類、程序組織、公共變量等方面做出了要求。規範分爲兩個級別——規則和建議。規則級的規範要求開發人員必須要遵守,建議級的規範開發人員應儘量遵守。
各項目組在用C++語言或基於C++語言的開發工具開發項目時,要遵守本規範。
2 編碼規範正文
以下是各條規範的具體內容。
2.1格式
對代碼書寫格式的要求。
2.1.1 空行的使用
規範級別:規則
規則描述:
●在頭文件和實現文件中,各主要部分之間要用空行隔開。
所謂文件的主要部分,包括:序言性註釋、防止被重複包含部分(只在頭文件中)、# include部分、#define部分、類型聲明和定義部分、實現部分等等。
●在一個函數中,完成不同功能的部分,要用空行隔開。
理由:
段落分明,提高代碼的可讀性。
2.1.2 哪裏應該使用空格
規範級別:規則
規則描述:
●在使用賦值運算符、邏輯運算符、位運算符、算術運算符等二元操作符時,在其兩邊各加一個空格。
例: nCount = 2;而不是 nCount=2;
● 函數的各參數間要用“,”和一個空格隔開。
例:void GetDate(int x, int y);
而不是void GetDate(int x,int y)或void GetDate(int x ,int y)。
理由:
提高代碼的可讀性。
2.1.3 哪裏不應該使用空格
規範級別:規則
規則描述:
●不要在引用操作符前後使用空格,引用操作符指“.”和“->”,以及“[]”。
●不要在“::”前後使用空格。
●不要在一元操作符和其操作對象之間使用空格,一元操作符包括“++”、“--”“!”、“&”“*”等。
理由:
提高代碼的可讀性。
舉例:
// 不要象下面這樣寫代碼:
m_pFont -> CreateFont();
//應該寫成這樣
m_pFont->CreateFont();
2.1.4 縮進
規範級別:規則
規則描述:
對程序語句要按其邏輯進行水平縮進,以兩個空格爲單位,使同一邏輯層次上的代碼在列上對齊。
理由:
提高代碼的可讀性。
2.1.5 長語句的書寫格式
規範級別:規則
規則描述:
較長的語句要分成多行書寫。長表達式要在低優先級操作符處分新行,操作符放在新行之首,劃分出的新行要進行適當的縮進,縮進長度以兩個空格或Tab符長度爲單位。
理由:
提高代碼的可讀性。
舉例:
// 下面是一個處理的較爲合理的例子
nCount = Fun1(n1, n2, n3)
+ (nNumber1 * GetDate(n4, n5, n6)) * nNumber1;
2.1.6 清晰劃分控制語句的語句塊
規範級別:規則
規則描述:
控制語句(if , for , while , do...whule)的語句部分一定要用 ‘{ ’和‘ }’括起來(即使只有一條語句),並且‘{ ’和‘ }’應處在同一列上。
理由:
這樣做,能夠劃分出清晰的語句塊,使語句的歸屬明確,使代碼更加容易閱讀和修改。
舉例:
//不要象下面這樣寫代碼:
if (x == 0)
return;
else
while (x > min)
x--;
// 應該這樣寫
if (x == 0)
{
return;
}
else
{
while (x > min)
{
x--;
}
}
2.1.7 一行只寫一條語句
規範級別:規則
規則描述:
一行只寫一條程序語句。
理由:
提高代碼的可讀性。
舉例:
// 不要這樣寫
x = x0; y = y0;
while(IsOk(x)) {x++;}
// 應該這樣寫代碼
x = x0;
y = y0;
while(IsOk(x))
{
x++;
}
2.1.8 一次只聲明、定義一個變量
規範級別:規則
規則描述:
一次(一條聲明、定義語句)只聲明、定義一個變量。
理由:
提高代碼的可讀性。
舉例:
// 應該這樣寫
int width;
int length;
// 不要這樣寫
int width, length;
2.1.9 在表達式中使用括號
規範級別:建議
規則描述:
對於一個表達式,在一個二元、三元操作符操作的操作數的兩邊,應該放置“(”和“)”。
理由:
避免出現不明確的運算、賦值順序,提高代碼的可讀性。
舉例:
// 下面這行代碼:
result = fact / 100 * number + rem;
//最好寫成這樣
result = ((fact / 100) * number) + rem;
2.1.10將操作符“*”、“&”和類型寫在一起
規範級別:規則
規則描述:
在定義指針、引用變量時,將操作符“*”、“&”和類型寫在一起。
理由:
統一格式,提高代碼的可讀性。
舉例:
// 不要象下面這樣寫代碼:
char *s;
//而應該寫成這樣
char* s;
2.2註釋
這一部分對程序註釋提出了要求。
程序中的註釋是程序與日後的程序讀者之間通信的重要手段。良好的註釋能夠幫助讀者理解程序,爲後續階段進行測試和維護提供明確的指導。
下面是關於註釋的基本原則:
1. 註釋內容要清晰明瞭,含義準確,防止出現二義性。
2. 邊寫代碼邊註釋,修改代碼的同時修改相應的註釋,保證代碼與註釋的一致性。
2.2.1 對函數進行註釋
規範級別:規則
規則描述:
●在函數的聲明之前,要給出精練的註釋(不必牽扯太多的內部細節),讓使用者能夠快速獲得足夠的信息使用函數。格式不做具體要求。
●在函數的定義之前,要給出足夠的註釋。註釋格式要求如下:
/*************************************************************************
【函數名稱】 (必需)
【函數功能】 (必需)
【參數】 (必需。標明各參數是輸入參數還是輸出參數。)
【訪問變量】 (必需。列出該函數訪問的全局變量、成員變量。)
【返回值】 (必需。解釋返回值的意義。)
【使用情況】 (必需。調用其它函數的情況,被調用的情況)
【開發者及日期】 (必需)
【版本】 (必需)
【更改記錄】 (若有修改,則必需註明)
*************************************************************************/
理由:
提高代碼的可讀性。
2.2.2 對類進行註釋
規範級別:規則
規則描述:
● 在類的聲明之前,要給出足夠而精練的註釋。註釋格式要求如下:
/*************************************************************************
【類名】 (必需)
【功能】 (必需)
【接口說明】 (必需)
【開發者及日期】 (必需)
【版本】 (必需)
【版權信息】 (可選)
【更改記錄】 (若修改過則必需註明)
*************************************************************************/
理由:
提高代碼的可讀性。
2.2.3 對文件進行註釋
規範級別:規則
規則描述:
在頭文件、實現文件的首部,一定要有文件註釋,用來介紹文件內容。註釋格式要求如下:
/*************************************************************************
【文件名】 (必需)
【功能模塊和目的】 (必需)
【開發者及日期】 (必需)
【版本】 (必需)
【版權信息】 (必需)
【更改記錄】 (若修改過則必需註明)
*************************************************************************/
理由:
提高代碼的可讀性。
2.2.4 對每個空循環體要給出確認性註釋
規範級別:建議
規則描述:
建議對每個空循環體給出確認性註釋。
理由:
提示自己和別人,這是空循環體,並不是忘了。
舉例:
while(g_bOpen == FALSE)
{
//空循環
}
2.2.5 對多個case語句共用一個出口的情況給出確認性註釋
規範級別:建議
規則描述:
建議對多個case語句共用一個出口的情況給出確認性註釋。
理由:
提示自己和別人,這幾個case語句確實是共用一個出口,並不是遺漏了。
舉例:
switch(nNumber)
{
case 1:
nCount++;
break;
case 2:
case 3:
nCount--;
break; // 當nNumber等於2或3時,進行同樣的處理
default:
break;
}
2.2.6 其它應該考慮進行註釋的地方
規範級別:建議
規則描述:
除上面說到的,對於以下情況,也應該考慮進行註釋:
l 變量的聲明、定義。通過註釋,解釋變量的意義、存取關係等;
例如:
int m_nNumber; //記錄圖形個數。被SetDate( )、GetDate( )使用。
l 數據結構的聲明。通過註釋,解釋數據結構的意義、用途等;
例如:
//定義結構體,存儲元件的端點。用於將新舊的端點對應。
typedef struct
{
int nBNN;
int nENN;
int nBNO;
int nENO;
}Element;
l分支。通過註釋,解釋不同分支的意義;
例如:
if(m_iShortRadio == 0) //三相的情況
{
strvC.Format("%-10.6f", vC);
straC.Format("%-10.6f", aC);
}
else if(m_iShortRadio == 1) //兩相的情況
{
strvC = _T("");
straC = _T("");
}
l調用函數。通過註釋,解釋調用該函數所要完成的功能;
例如:
SetDate(m_nNumber ); //設置當前的圖形個數。
l 賦值。通過註釋,說明賦值的意義;
例如:
m_bDraw = true; //將當前設置爲繪圖狀態
l 程序塊的結束處。通過註釋,標識程序塊的結束。
例如:
if (name = = White)
{
…
if (age = = 20)
{
…
}//年齡判斷、處理結束
…
}//姓名判斷、處理結束
l其它有必要加以註釋的地方;
理由:
提高代碼的可讀性。
2.2.7 行末註釋儘量對齊
規範級別:建議
規則描述:
同一個函數或模塊中的行末註釋應儘量對齊。
理由:
提高代碼的可讀性。
舉例:
nCount = 0; //計數器,表示正在處理第幾個數據塊
BOOL bNeedSave; //是否保存從服務器返回的數據
BOOL bReturnCache; //是否將Cache中的內容返回客戶端
DWORD BytesWritten; //寫入的數據長度
2.2.8 註釋量
規範級別:規則
規則描述:
註釋行的數量不得少於程序行數量的1/3。
2.3命名
對標識符和文件的命名要求。
2.3.1 標識符命名要求
規範級別:規則
規則描述:
在程序中聲明、定義的變量、常量、宏、類型、函數,在對其命名時應該遵守統一的命名規範。具體要求如下:
<! l一般變量
一般變量名應以小寫字母打頭,各英文描述單詞的首字母分別大寫,其他字母一律小寫。對於不同作用域的變量,其命名要求如下表所示:
表2-1 變量命名
變量種類 |
前綴要求 |
示例 |
全局變量 |
g_ |
g_Number |
全局指針變量 |
g_p |
g_pNumber |
對象級變量(類內數據成員) 文件作用域變量(文件中靜態變量) |
m_ |
m_Number |
對象級指針變量(類內指針數據成員) 文件作用域指針變量(文件中靜態指針變量) |
m_p |
m_pNumber |
函數級變量(局部變量) |
無要求 |
number |
函數級指針變量(局部指針變量) |
p |
pNumber |
上表列出了對變量命名的基本要求。項目組或程序員可在該要求上再進行細化,但必須保證符合該要求。
<! l常量
常量的名字要全部大寫。常量指:
const修飾的量。如const int NUMBER = 100;
枚舉量。如enum{ ONE,TWO,THREE };
<! l宏
所有用宏形式定義的名字,包括宏常量和宏函數,名字要全部大寫。
<! l類型
自定義類型名應以大寫字母打頭。C++中自定義類型包括:class、struct、enum、union、typedef聲明的類型、namespace。
例如:typedef struct Student;
class CMsgDialog;
<! l函數
函數名應以大寫字母打頭。
例如:void GetCount();
下面還有一些在命名時應該遵守的基本規範:
<! l名中含多於一個單詞時,每個單詞的第一個字母大寫。
例如:m_LastCount 中要大寫L和C;
<! l不要使用以下劃線“_”打頭的標識符。
例如:_bFind 是不允許出現的變量;
<! l不要使用僅用大小寫字母區分的名稱。
例如:m_bFind 和 M_BFIND;
<! l儘量使用有意義的名字。應做到見其名知其意。
例如:m_strError 表示錯誤的字符串;
理由:
減少命名衝突;提高代碼的可讀性。
2.3.2 標識符長度要求
規範級別:規則
規則描述:
在程序中聲明、定義的變量、常量、宏、類型、函數,它們的名字長度要在4至25個字符之內(下限不包括前綴,上限包括名字中所有的字符)。
對於某些已經被普遍認同的簡單命名,可不受本規則的限制。如for循環的循環記數變量,可使用 i 、j 等簡單字符命名。
理由:
名字長度應該在一個恰當的範圍內,名字太長不夠簡潔,名字太短又不能清晰表達含義。
2.3.3 文件命名要求
規範級別:建議
規則描述:
代碼文件的名字要與文件中聲明、定義的類的名字基本保持一致,使類名與類文件名建立聯繫。
理由:
使應用程序容易理解。
舉例:
將類CMsgDialog的頭文件和實現文件命名爲msgdialog.h和msgdialog.cpp就是一種比較簡單、恰當的方法。
2.4語句
對具體程序語句的使用要求。
2.4.1 一條程序語句中只包含一個賦值操作符
規範級別:建議
規則描述:
在一條程序語句中,只應包含一個賦值操作符。賦值操作符包括:=, +=, -=, *=, /=, %=, >>=, <<=, &=, |=,^=, ++, --。
理由:
避免產生不明確的賦值順序。
舉例:
// 不要這樣寫
b = c = 5;
a = (b * c) + d++;
// 應該這樣寫
c = 5;
b = c;
a = (b * c) + d;
d++;
2.4.2 不要在控制語句的條件表達式中使用賦值操作符
規範級別:建議
規則描述:
不要在控制語句if, while, for 和 switch的條件表達式中使用賦值操作符。賦值操作符包括:=, +=, -=, *=, /=, %=, >>=, <<=, &=, |=, ^=,++,--。
理由:
一個類似於 if (x = y)這樣的寫法是不明確、不清晰的,代碼的作者也許是想寫成這樣: if (x == y)。
舉例:
//不要象下面這樣寫代碼:
if (x -= dx)
{
...
}
//應該這樣寫:
x -= dx;
if (x)
{
...
}
2.4.3 賦值表達式中的規定
規範級別:建議
規則描述:
在一個賦值表達式中:
• 一個左值,在表達式中應該僅被賦值一次。
• 對於多重賦值表達式,一個左值在表達式中僅應出現一次,不要重複出現。
理由:
避免產生不明確的賦值順序。
舉例:
//不要象下面這樣寫代碼:
i = t[i++]; //一個左值,在表達式中應該僅被賦值一次
a = b = c + a; //對於多重賦值表達式,一個左值在表達式中僅應出現一次,不能重複出現。
i = t[i] = 15; //對於多重賦值表達式,一個左值在表達式中僅應出現一次,不能重複出現。
2.4.4 使用正規格式的布爾表達式
規範級別:建議
規則描述:
對於if, while, for等控制語句的條件表達式,建議使用正規的布爾格式。
理由:
使代碼更容易理解。
舉例:
//不要象下面這樣寫代碼:
while(1)
{
...
}
if(test)
{
...
}
for(i = 1; function_call(i); i++)
{
...
}
//最好這樣寫:
AlwaysTrue = true;
while(AlwaysTrue == true)
{
...
}
if(test == true)
{
...
}
for(i = 1; function_call(i) == true; i++)
{
...
}
2.4.5 禁用Goto語句
規範級別:規則
規則描述:
程序中不要使用goto語句。
理由:
這條規則的目的是爲了確保程序的結構化,因爲濫用goto語句會使程序流程無規則,可讀性差。
Goto語句只在一種情況下有使用價值,就是當要從多重循環深處跳轉到循環之外時,效率很高,但對於一般要求的軟件,沒有必要費勁心思追求多麼高的效率,而且效率主要是取決於算法,而不在於個別的語句技巧。
2.4.6 程序中禁用break、continue
規範級別:規則
規則描述:
在控制語句 (for, do, while) 塊中,禁止使用Break和continue。
在switch中的case語句塊不受該規則限制。
理由:
在控制語句 (for, do, while) 塊中使用Break和continue,會打亂代碼結構化的流程,使代碼的可讀性降低。
2.4.7 字符串的賦值
規範級別:規則
規則描述:
字符串的賦值應採用_T(“”)模式。
理由:
改善可移植性。
舉例:
//不要象下面這樣寫代碼:
Cstring strError = “syntax error”;
//應該這樣寫:
Cstring strError = _T(“syntax error”);
2.4.8 避免對浮點數值類型做精確比較
規範級別:規則
規則描述:
不要對浮點類型的數據做等於、不等於這些精確的比較判斷,要用範圍比較代替精確比較。
理由:
由於存在舍入的問題,計算機內部不能精確的表示所有的十進制浮點數,用等於、不等於這種精確的比較方法就可能得出與預期相反的結果。所以應該用大於、小於等範圍比較的方法代替精確比較的方法。
舉例:
//不要象下面這樣寫代碼:
float number;
… …
if (number = = 0) //精確比較
… …
2.4.9 new 和 delete
規範級別:規則
規則描述:
局部的new 和 delete 要成對出現;
new要與delete對應,new[]要與delete[]對應。
理由:
防止內存泄露。
2.4.10對switch語句中每個分支結尾的要求
規範級別:規則
規則描述:
switch語句中的每一個case分支,都要以break作爲分支的結尾(幾個連續的空case語句允許共用一個)。
理由:
使代碼更容易理解;減少代碼發生錯誤的可能性。
2.4.11switch語句中的default分支
規範級別:規則
規則描述:
在switch語句塊中,一定要有default分支來處理其它情況。
理由:
用來處理switch語句中默認、特殊的情況。
2.4.12對指針的初始化
規範級別:建議
規則描述:
在定義指針變量的同時,對其進行初始化。如果定義時還不能爲指針變量賦予有效值,則使其指向NULL。
理由:
減少使用未初始化指針變量的機率。
舉例:
// 不要這樣寫代碼
int* y ;
y = &x ;
...
// 應該這樣寫
int* y = &x;
...
2.4.13釋放內存後的指針變量
規範級別:建議
規則描述:
當指針變量所指的內存被釋放後,應該賦予指針一個合理的值。除非該指針變量本身將要消失這種情況下不必賦值,否則應賦予NULL。
理由:
保證指針變量在其生命週期的全過程都指向一個合理的值。
2.4.14指針指向的數據成員的訪問方式
規範級別:規則
規則描述:
在代碼中用ptr->fld的形式代替(*ptr).fld的形式。
2.5函數
對函數的要求。
2.5.1 明確函數功能
規範級別:規則
規則描述:
函數體代碼長度不得超過100行(不包括註釋)。
理由:
明確函數功能(一個函數僅完成一件事情),精確(而不是近似)地實現函數設計。
2.5.2 將重複使用的代碼編寫成函數
規範級別:建議
規則描述:
將重複使用的簡單操作編寫成函數。
理由:
對於重複使用的功能,雖然很簡單,也應以函數的形式來處理,這樣可以簡化代碼,使代碼更易於維護。
2.5.3 儘量保持函數只有唯一出口
規範級別:規則
規則描述:
應該儘量保證一個函數只有一個出口。
理由:
增加函數的可靠性。
2.5.4 函數聲明和定義的格式要求
規範級別:規則
規則描述:
在聲明和定義函數時,在函數參數列表中爲各參數指定類型和名稱。
理由:
提高代碼的可讀性,改善可移植性。
舉例:
// 不要象下面這樣寫代碼:
f(int, char*); //函數聲明
f(a, b) //函數定義
int a;
char* b
{
...
}
// 應該這樣寫:
f(int a, char* b);
f(int a, char* b)
{
...
}
2.5.5 爲函數指定返回值
規範級別:規則
規則描述:
要爲每一個函數指定它的返回值。如果函數沒有返回值,則要定義返回類型爲void。
理由:
提高代碼的可讀性;改善代碼的可移植性。
2.5.6 在函數調用語句中不要使用賦值操作符
規範級別:建議
規則描述:
函數調用語句中,在函數的參數列表中不要使用賦值操作符。賦值操作符包括=, +=, -=, *=, /=, %=, >>=, <<=, &=, |=, ^=,++,--。
理由:
避免產生不明確的賦值順序。
舉例:
// 不要象下面這樣寫代碼:
void fun1(int a);
void fun2(int b)
{
fun1(++b); //注意這裏!
}
2.5.7 保護可重入函數中的全局變量
規範級別:規則
規則描述:
編寫可重入函數時,若操作全局變量,則應加以保護。
舉例:
如果全局變量不加以保護,當多個線程調用此函數時,很可能使此變量變爲不可知狀態。
例如:假設 Exam是int型全局變量,函數Squre_Exam返回Exam平方值,如下函數不具有可重入性。
Unsigned int example (int para)
{
unsigned int temp;
<!--
Exam = para;
temp = Square_Exam();
return temp;
}
此函數若被多個線程調用, Exam 可能成爲未知的。
可改爲如下方式:
Unsigned int example (int para)
{
unsigned int temp;
[申請信號量操作]
Exam = para;
temp = Square_Exam();
[釋放信號量操作]
return temp;
}
2.6類
對類的要求。
2.6.1 關於默認構造函數
規範級別:規則
規則描述:
爲每一個類顯示定義默認構造函數。
理由:
確保類的編寫者考慮在類對象初始化時,可能出現的各種情況。
舉例:
class CMyClass
{
CMyClass();
...
};
2.6.2 關於拷貝構造函數
規範級別:規則
規則描述:
當類中包含指針類型的數據成員時,必須顯示的定義拷貝構造函數。建議爲每個類都顯示定義拷貝構造函數。
理由:
確保類的編寫者考慮類對象在被拷貝時可能出現的各種情況。
舉例:
class CMyClass
{
...
CMyClass(CMyClass& object);
...
};
2.6.3 爲類重載“=”操作符
規範級別:規則
規則描述:
當類中包含指針類型的數據成員時,必須顯示重載“=”操作符。建議爲每個類都顯示重載“=”操作符。
理由:
確保類的編寫者考慮將一個該類對象賦值給另一個該類的對象時,可能出現的各種情況。
舉例:
// 應該這樣寫代碼
class CMyClass
{
...
operator = (const CMyClass& object);
...
};
2.6.4 關於析構函數
規範級別:規則
規則描述:
爲每一個類顯示的定義析構函數。
理由:
確保類的編寫者考慮類對象在析構時,可能出現的各種情況。
舉例:
class CMyClass
{
...
~CMyClass (CMyClass& object);
...
};
2.6.5 虛擬析構函數
該規則參考自《Effective C++》中的條款 14。
規範級別:規則
規則描述:
基類的析構函數一定要爲虛擬函數(virtual Destructor)。
理由:
保證類對象內存被釋放之前,基類和派生類的析構函數都被調用。
2.6.6 不要重新定義繼承來的非虛函數
規範級別:規則
規則描述:
在派生類中不要對基類中的非虛函數重新進行定義。如果確實需要在派生類中對該函數進行不同的定義,那麼應該在基類中將該函數聲明爲虛函數;
理由:
不要忘了,當通過一個指向對象的指針調用成員函數時,最終調用哪個函數取決於指針本身的類型,而不是指針當前所指向的對象。
2.6.7 用內聯函數代替宏函數
規範級別:建議
規則描述:
用內聯函數代替宏函數。
理由:
同宏函數相比,內聯函數不但具有宏函數的效率,而且使用起來更安全。
2.6.8 如果重載了操作符"new",也應該重載操作符 "delete"
該規則參考自《Effective C++》中的條款10。
規範級別:規則
規則描述:
如果你爲一個類重載了操作符new,那你也應該爲這個類重載操作符delete。
理由:
操作符new和操作符delete需要一起合作。
2.6.9 類數據成員的訪問控制
規範級別:規則
規則描述:
類對外的接口應該是完全功能化的,類中可以定義Public的成員函數,但不應該有Public的數據成員。
理由:
要想改變對象的當前狀態,應該通過它的成員函數來實現,而不應該通過直接設置它的數據成員這種方法。一個類的數據成員應該聲明爲private的,最起碼也應該是protected的。
2.6.10限制類繼承的層數
規範級別:建議
規則描述:
當繼承的層數超過5層時,問題就很嚴重了,需要有特別的理由和解釋。
理由:
●很深的繼承通常意味着未做通盤的考慮;
●會顯著降低效率;
●可以嘗試用類的組合代替過多的繼承;
●與此類似,同層類的個數也不能太多,否則應該考慮是否要增加一個父類,以便做某種程度上的新的抽象,從而減少同層類的個數。
2.6.11慎用多繼承
規範級別:建議
規則描述:
C++提供多繼承的機制。多繼承在描述某些事物時可能是非常有利的,甚至是必須的,但我們在使用多繼承的時,一定要慎重,在決定使用多繼承時,確實要有非常充分的理由。
理由:
多繼承會顯著增加代碼的複雜性,還會帶來潛在的混淆。比如在很多C++書籍中提到的菱形繼承問題,如下圖所示:
圖2-1 菱形繼承
A派生子類B、C,D多繼承於B、C。這種情況下,會導致類D的對象中有兩個類A子對象。
2.6.12考慮類的複用
規範級別:建議
規則描述:
類設計的同時,考慮類的可複用性。
2.7程序組織
對程序組織的要求。
2.7.1 一個頭文件中只聲明一個類
規範級別:規則
規則描述:
在一個頭文件中,只應該包含對一個類的聲明(嵌套類的情況除外)。頭文件是指以.h、.hh、.H、.hxx、.hpp爲後綴的文件。
理由:
提高代碼的可讀性。
2.7.2 一個源文件中只實現一個類
規範級別:規則
規則描述:
在一個源文件中定義的每一個函數,都應該屬於同一個類,即對一個類的實現描述要獨佔一個文件。源文件指以*.cc, *.cxx, *.cpp, *.C or *.c爲後綴的代碼文件。
理由:
提高代碼的可讀性。
2.7.3 頭文件中只包含聲明,不應包含定義
規範級別:規則
規則描述:
在頭文件中只包含聲明,不要包含全局變量和函數的定義。頭文件指以.h、 .hh、.H、 .hxx、.hpp爲後綴的代碼文件。
內聯函數的情況除外。
理由:
在頭文件中只應該包含各種聲明,而不應該包含具體的實現。
2.7.4 源文件中不要有類的聲明
規範級別:規則
規則描述:
在源文件中只應該包含對類的實現,不應該包含任何類的聲明。類聲明應該統一放到頭文件中去。源文件指以*.cc, *.cxx, *.cpp, *.C or *.c爲後綴的代碼文件。
理由:
提高代碼的可讀性。
2.7.5 可被包含的文件
規範級別:規則
規則描述:
只允許頭文件被包含到其它的代碼文件中去。
理由:
改善程序代碼的組織結構。
2.7.6 避免頭文件的重複包含
規範級別:規則
規則描述:
頭文件的格式應該類似於:
#ifndef <IDENT>
#define <IDENT>
...
...
#endif
或者
#if !defined (<IDENT>)
#define <IDENT>
...
...
#endif
上面的<IDENT>是一個標識字符串,要求該標識字符串必須唯一。建議使用該文件的答謝文件名。
理由:
避免對同一頭文件的重複包含。
舉例:
// 對於文件audit.h,它的文件結構應該爲:
#ifndef AUDIT_H
#define AUDIT_H
...
...
#endif
2.8 公共變量
對公共變量(全局變量)的要求。
2.8.1 嚴格限制公共變量的使用
規範級別:建議
規則描述:
在程序中要儘可能少的使用公共變量。在決定使用一個公共變量時,要仔細考慮,權衡得失。
理由:
公共變量會增大模塊間的耦合。
2.8.2 明確公共變量的定義
規範級別:規則
規則描述:
當你真的決定使用公共變量時,要仔細定義並明確公共變量的含義、作用、取值範圍、與其它變量間的關係。明確公共變量與操作此公共變量的函數之間的關係,如訪問、修改和創建等。
2.8.3 防止公共變量與局部變量重名
規範級別:規則
規則描述:
防止公共變量與局部變量重名。
2.9 其它
下面這幾條要求,不適合合併到上面任何一類,所以單獨作爲一部分。
2.9.1 不要使用結構體
規範級別:建議
規則描述:
在C++中,不要再使用struct。
理由:
以符合面向對象的思想。
2.9.2 不要使用聯合體
規範級別:建議
規則描述:
在C++中,不要再使用union。
理由:
●由於union成員公用內存空間所以容易出錯,並且維護困難;
●使用union通常意味着非面向對象的方法。
2.9.3 用常量代替宏
規範級別:規則
規則描述:
使用const來定義常量,代替通過宏來定義常量的方法。
理由:
在不損失效率的同時,使用const常量比宏更加安全。
舉例:
//宏定義的方法
#define string "Hello world!"
#define value 3
//常量定義的方法可以代替宏,且要更好
const char* string = "Hello world!";
const int value = 3;
2.9.4 括號在宏中的使用
規範級別:規則
規則描述:
對於宏的展開部分,在宏的參數出現的地方要加括號“()”。
理由:
保證宏替換的安全,同時提高代碼的可讀性。
舉例:
// 不要這樣寫
#define GET_NAME(obj,ind) obj->name[ind]
// 應該這樣寫
#define GET_NAME(obj,ind) (obj)->name[ind]
2.9.5 儘量使用C++風格的類型轉換
該規則參考自《More Effective C++》中的條款2。
規範級別:建議
規則描述:
用C++提供的類型轉換操作符(static_cast,const_cast, dynamic_cast和reinterpret_cast)代替C風格的類型轉換符。
理由:
C風格的類型轉換符有兩個缺點:
1 允許你在任何類型之間進行轉換,即使在這些類型之間存在着巨大的不同。
2 在程序語句中難以識別。
2.9.6 將不再使用的代碼刪掉
規範級別:規則
規則描述:
將程序中不再用到的、註釋掉的代碼及時清除掉。
理由:
理由不用做太多的解釋了吧?沒有用的東西就應該清理掉。如果覺得這些代碼你可能以後會用到,可以備份到其它地方,而不要留在正式的版本里。
3 結束
以上就是我們要求C++程序遵守的規範的全部內容。