C++:代碼規範

一。文件和目錄

在C/C++編程中,應該使用如下的文件名後綴:
C++的頭文件:.hpp(系統自動生成時允許.h,比如VC)
C++的Inline函數實現頭文件:_I.hpp
C++的源文件:.cpp
C的頭文件:.h
C的源文件:.c
Perl編程中:
Perl程序的源文件:.pl
C#編程中:
C#程序的源文件:.cs
Shell編程中:
Shell腳本的源文件:.sh

使用統一而且通用的文件名後綴可以增加可讀性和移植性,還能簡化諸如make等工具的依賴規則。
使用hpp和cpp是因爲這是VC可以支持的比較通用的文件名後綴,也是UNIX可以接受的。使用.hpp而不是.h是爲了區分C++和C程序的頭文件。(建議自己生成的頭文件使用.hpp。編譯器生成的頭文件允許使用.h)
在C++中不使用.i而是用_I.hpp是因爲大多數編譯器不認識.i這種後綴,或者.i文件對於編譯器有特殊的用途,會引起衝突。使用_I.hpp而不是I.hpp是因爲前者更加清楚一點。
擴展名都是用小寫是因爲有的平臺是大小寫區分的,統一用小寫有利 於增加平臺間的移植性。

二。 排版

程序塊採用縮進風格編寫,每次用4各空格鍵。
在程序適當的地方加入空行
說明
在以下地方應該是用空行分開:

  1.   函數之間應該用空行分開;
    
  2.   一組局部變量聲明和代碼之間用空行分開;
    
  3.   用空行將代碼按照邏輯片斷劃分;
    
  4.   除非函數非常簡單(如只有一兩條語句),否則函數返回語句和其他語句用空行分開;
    
  5.   每個類聲明之後應該加入空格同其他代碼分開;
    

原因
空行得體(不過多也不過少)將使程序的佈局更加清晰。空行不會浪費內存,雖然打印含有空行的程序是會多消耗一些紙張,但是值得。
函數中較長的變量聲明分成多行編寫
一行只寫一條語句

if、for、do、while等語句自佔一行,其後無論執行語句多長,都應該使用{}
說明
例外的情況是:如果存在多個if…else…語句並列,則else可以和if放在同一行。
如下的寫法不合規範:
if ( 0 == a) return NULL;
C/C++應該這樣寫:
if ( 0 == a)
{
return value;
}
Java可以這樣寫
if ( 0== a) {
return value;
}

如下的寫法不合規範:
if ( 0 == a) return NULL;
C/C++應該這樣寫:
if ( 0 == a)
{
return value;
}
Java可以這樣寫
if ( 0== a) {
return value;
}

類內普通成員、類內靜態數據成員、全局變量、文件作用域靜態變量分別使用i_或者m_,c_,g_,f_;它們的含義分別是:instance scope,class scope;global,file scope

三。註釋

文件頭註釋
說明
使用C/C++或者Java編程的時候,在每個源程序文件的頭部進行如下的註釋:
/**

  • File: WinMain.cpp
  • Purpose: The main program of HelloWorld. It calls init functions and
  • contains the message loop.
    
  • @author Tom
  • @version 1.0 2002/10/28
  • Copyright © 2000, 2002, Yashentech, Inc.

*/
注意文件頭註釋爲javadoc的文檔註釋類型,下面的函數、類和結構的註釋也是使用javadoc的文檔註釋類型。
如果註釋的內容超過一行,縮進也是四個空格。

使用C/C++或者Java編程的時候,每一個Public類型函數開頭要有如下的註釋,其他函數建議有(缺省構造函數、拷貝構造函數和析構函數可以不註釋,成員屬性的Set和Get方法可以不註釋):
/**

  • :<對函數的簡單描述>
  • @param <函數參數> <對函數參數的簡單描述>
  • @return <函數的返回值> <對返回值的簡單描述>
  • @throws <拋出的異常><拋出的異常的描述>
  • @see <參見的內容>
  • @deprecated <刪除的內容>
    */
    如果函數沒有返回值,則這樣書寫:@return void,如果函數沒有參數或者異常拋出,@param和@throws可以省略。@see和@deprecated標籤只在必要的時候使用就可以了。

類註釋
說明
使用C/C++或者Java編程的時候,每一個類(或者sturct、union)開頭要有如下的註釋:
/**

  • :<對這個類的簡單描述>
  • @author <作者的名字>
  • @version <版本信息>
  • @see <參見的內容>
  • @deprecated <刪除的內容>
    */
    其中class-type說明這是個類,還是struct,還是union、interface等,@see和@deprecated標籤只在必要的時候使用就可以了。

四。判斷語句

對於判斷語句,遵循以下的寫法(假設變量名爲flag)

  1.   如果flag是布爾型變量,則如此書寫:
    

if (flag)
if (!flag)
2. 如果flag是浮點型,避免使用等於或者不等於判斷:
如這樣的寫法不好:
if (flag == 0)
而應該使用類似這種大於等於或者小於等於進行判斷:
if (flag >= -0.000001 && flag <= 0.000001)
3. 如果flag是指針,避免它和0直接進行比較:
如這樣的寫法不對:
if ( flag == 0)

if ( flag != 0)
而應該寫成:
If ( NULL == flag)

If ( NULL != flag)
4. 如果flag是整數,避免下面的寫法:
if (flag)

if (!flag)
而應該寫成
if (0 == flag)

if (0 != flag)

五。const約束

儘量使用const約束
示例
const char* ClassA::GetData(int const* pValue) const
{
return m_pData;
}
第一個const 表示返回的指針所指向的內容在外部不可修改,第二個表示傳入的參數指針所指向的內容在函數內不可修改,第三個表示該函數不會造成類成員的變化;
原因
使用const約束能提高安全性,減少調用者和被調用對象的耦合程度,降低維護的複雜程度。

六。類成員初始化
在分配存儲時初始化成員
說明
對於簡單數據類型的成員,在分配存儲空間時,而不是構造函數初內賦值。
示例
ClassA::ClassA()
:m_pData(NULL),
,m_nCount(0)
{
//…
}
而不是
ClassA::ClassA()
{
m_pData = NULL;
m_nCount = 0;
//…
}
原因
在給對象分配內存時即填充值,而不是構造函數執行時再次執行賦值語句。也有利於初始化代碼的檢查,避免因成員未初始化造成未知結果。養成在頭文件添加申明時隨之添加初始化的習慣。

七。資源
建議儘量使用現有的免費資源
www.sourceforge.net。
C++單元測試建議使用CppUnit;
C++多線程編程建議使用ZThread;
C++日誌編程建議使用Log4Cpp;
C++數據庫接口編程建議使用Odbc,ADO,SqlApi,OTL;
Java數據庫接口編程建議使用Jdbc,hibernate等。

1 命名常量應當使用全大寫字母,單詞之間使用下劃線連接
Common practice in the C++ development community. 通常情況下,常量的使用應該控制在最小限度內,在很多情況下可以把值變爲方法:

int getMaxIterations() // NOT: MAX_ITERATIONS = 25

{

return 25;

}

這樣既清晰閱讀,又確保了這個接口對於類來說值是統一的。
2
名函數時一定要使用動詞並且起始字母小寫。
getName(), computeTotalWidth()
3
命名空間應該使用小寫
model::analyzer, io::iomanager, common::math::geometry
C++社區常用規範。
4
命名模板類型應該使用一個單一的大寫字母。
template … template<class C, class D> …
C++社區常用規範。 這樣使得模板名稱與其他使用的名稱清晰的獨立出來
5
簡略詞必須不使用全大寫
exportHtmlSource(); // NOT: exportHTMLSource();openDvdPlayer(); // NOT: openDVDPlayer();
使用全大寫的縮略詞會導致衝突,像dVD,hTML這類的同樣也不利於閱讀,而且當略縮詞後面連接了一個單詞後,會減少後面單詞的可讀性。
6
全局變量應當使用操作符::
::mainWindow.open(), ::applicationContext.getName()
通常應該避免使用全局變量,考慮單例模式的對象來代替。
7
私有類變量應該使用下劃線字尾.
class SomeClass { private: int length_; }
除了變量的名稱和類型,作用域是一個變量最重要的屬性。 its name and its type, the scopeof a variable is its most important feature. 通過下劃線來區分局部變量和類的私有變量是很方便的事情。因爲類變量具有比函數變量更大的作用域因此應當值得程序員的注意。同時還使得當變量出現問題時,更方便的解決。 void setDepth (int depth) { depth_ = depth; }這種方案的一個問題就是應當使用下劃線做前綴還是後綴,這兩種方法都被廣泛的應用,但後綴更加值得推薦一下,因爲我們覺得這樣使得單詞看起來更舒服。值得注意的是變量作用域標識的問題已經有很長時間了,這個指南中這條規則被更多的應用了。
8
通用的變量名應該與類型名一致
void setTopic(Topic* topic) // NOT: void setTopic(Topic* value) // NOT: void setTopic(Topic* aTopic) // NOT: void setTopic(Topic* t)void connect(Database* database) // NOT: void connect(Database* db) // NOT: void connect (Database* oracleDB)
通過減少不同變量名等方法來減少代碼的複雜度,同樣使得通過變量名猜測變量類型變得容易。如果某些情況下無法滿足這條指南,非通用的變量會有一個特殊的角色,那麼這些變量可以把角色和類型聯合起來: Point startingPoint, centerPoint; Name loginName;
9 變量的作用域長,使用長變量名,變量作用域短,使用短變量名。

10
對象名是一種暗示,應該避免再次出現在方法中
line.getLength(); // NOT: line.getLineLength();
在類定義時函數看起來似乎正常,但在上例中可以看的很清楚,多餘了。

函數命名
11
當一個屬性被允許修改,那麼必須要通過使用get/set函數
employee.getName();employee.setName(name);

12
可以使用compute命名需要在函數內進行計算的函數
valueSet->computeAverage();matrix->computeInverse()
13

可以使用find命名需要在函數內進行查找的函數
vertex.findNearestVertex(); matrix.findMinElement();
14
initialize 可以用來命名一個對象或強模板的建立。
printer.initializeFontSet();
15
. 代表着可視化組件的變量,應該具有組件類型的後綴名。
mainWindow, propertiesDialog, widthScale, loginText,leftScrollbar, mainForm, fileMenu, minLabel, exitButton, yesToggle etc.
增加可讀性,可以直觀的看出變量類型和對象資源。
16
枚舉常量應具有一個共同的前綴類型名
enum Color { COLOR_RED, COLOR_GREEN, COLOR_BLUE };
這樣命名增加了額外信息,哪裏可以找到這些變量、哪幾種常量是一起的以及代表了什麼樣的內容。一種替代方式是保持通過類型進行引用Color::RED, Airline::AIR_FRANCE注意枚舉類型的變量名應該是單數形式enum Color {…}.一個複數的名字儘管看起來沒有什麼區別,但在使用時看起來非常愚蠢。
include

17
頭文件必須要包含一個頭文件守護
#ifndef COM_COMPANY_MODULE_CLASSNAME_H#define COM_COMPANY_MODULE_CLASSNAME_H :#endif // COM_COMPANY_MODULE_CLASSNAME_H
這樣的語法結構用來避免編譯錯誤。這樣命名統一了頭文件出現在源文件中的位置,避免了名字衝突。
18
Include語句應當按組排列,按照在系統中的位置進行排序,低等級的在最前方聲明,每個組之間保留一個空行。
#include #include #include <qt/qbutton.h>#include <qt/qtextfield.h> #include “com/company/ui/PropertiesDialog.h”#include “com/company/ui/MainWindow.h”
除了可以給讀者一個清晰的包含文件的結構,還可以直觀的看出使用了哪些模塊。包含文件的路徑永遠不要使用絕對路徑,編譯器的指令才應用來指定包含文件的根目錄。

19
類一定要按照public、protected和private的順序來聲明。每種類型必須要精確的組織出來,不應當有混合情況。(All sections must be identified explicitly. Not applicable sections should be left out. )

順序就是最常用的放到第一位,這樣當需要使用這個類時,可以在讀到代碼段protected或private時停止。
20
類型轉換必須要表示出來,不要依靠隱藏的類型轉換
floatValue = static_cast(intValue); // NOT: floatValue = intValue;
這樣程序員表面了他意識到了不同類型的轉換,而需要進行。
21
類變量不應當被聲明爲public

public變量會破壞C++的信息隱藏和抽象。使用私有變量和訪問函數來代替。有一種例外情況是當類像C中的結構體一樣時,只包含數據。值得注意結構體在C++中只是爲了與C語言的兼容性,因此應當儘量不使用struct而是用類。
22
C++ pointers and references should have their reference symbol next to the type rather than to the name.
float* x; // NOT: float *x; int& y; // NOT: int &y;
The pointer-ness or reference-ness of a variable is a property of the type rather than the name. C-programmers often use the alternative approach, while in C++ it has become more common to follow this recommendation.
23 無限循環中應當使用while(true)

24複雜的條件判斷必須避免,使用臨時的布爾變量保存

25
浮點常數應當帶有小數點和至少一位小數。
double total = 0.0; // NOT: double total = 0;double speed = 3.0e8; // NOT: double speed = 3e8;double sum;:sum = (a + b) * 10.0;
強調了整數與浮點數的區別,同樣,像最後的例子裏,他表達了變量(sum)的類型,這僅僅從(a+b)中是無法看出來的。

  1. Names representing types must be in mixed case starting with upper case
    代表類型的名字必須首字母大寫並且其它字母大小寫混合
    例如:Line, SavingsAccount
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章