C++代碼規範

                                                            目錄

一、       頭文件    1

1.     define的保護... 1

2.     頭文件依賴... 1

3.     內聯函數... 1

4.     -inl.h文件... 1

5.     函數參數順序... 1

6.     包含文件的名稱及次序... 2

二、       作用域    3

1.     非成員函數、靜態成員函數和全局函數... 3

2.     局部變量... 3

3.     全局變量... 3

三、           3

1.     構造函數(Constructor)的職責... 4

2.     默認構造函數(Default Constructors... 4

3.     明確的構造函數(Explicit Constructors... 4

4.     拷貝構造函數(Copy Constructors... 5

5.     結構體和類(Structs vs. Classes... 5

6.     繼承(Inheritance... 5

7.     接口(Interface... 5

8.     操作符重載(Operator Overloading... 6

9.     存取控制(Access Control... 6

10.        聲明次序(Declaration Order... 6

11.        編寫短小函數(Write Short Functions... 7

四、       其他C++特性    7

1.     引用參數(Reference Arguments... 7

2.     函數重載(Function Overloading... 7

3.     缺省參數(Default Arguments... 7

4.     友元(Friends... 7

5.     異常(Exceptions... 7

6.     類型轉換(Casting... 7

7.     前置自增和自減(Preincrementand Predecrement... 7

8.     const的使用(Use of const... 8

9.     整型(Integer Types... 8

10.        預處理宏(Preprocessor Macros... 8

11.        0NULL0 and NULL... 9

12.        sizeofsizeof... 9

13.        Boost庫(Boost... 9

五、       命名約定    9

1.     通用命名規則(General Naming Rules... 9

2.     文件命名(File Names... 10

3.     類型命名(Type Names... 11

4.     變量命名(Variable Names... 11

5.     常量命名(Constant Names... 12

6.     函數命名(Function Names... 12

7.     命名空間(Namespace Names... 12

8.     枚舉命名(Enumerator Names... 13

9.     宏命名(Macro Names... 13

六、       註釋                                                      13

1.     註釋風格(Comment Style... 13

2.     TODO註釋(TODO Comments... 15

七、       格式                                                      15

1.     行長度(Line Length... 15

2.     ASCII字符(Non-ASCII Characters... 15

3.     空格縮進... 15

4.     函數聲明與定義(Function Declarations andDefinitions... 15

5.     函數調用(Function Calls... 17

6.     條件語句(Conditionals... 18

7.     循環和開關選擇語句(Loops and Switch Statements... 19

8.     指針和引用表達式(Pointers and ReferenceExpressions... 19

9.     布爾表達式(BooleanExpressions... 20

10.        函數返回值(Return Values... 21

11.        變量及數組初始化(Variable and ArrayInitialization... 21

12.        預處理指令(Preprocessor Directives... 21

13.        類格式(Class Format... 21

14.        初始化列表(Initializer Lists... 22

15.        命名空間格式化(Namespace Formatting... 23

16.        水平留白(Horizontal Whitespace... 23

17.        垂直留白(Vertical Whitespace... 25

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


 

一、       頭文件

通常,每一個.cpp文件(C++的源文件)都有一個對應的.h文件(頭文件),也有一些例外,如單元測試代碼和只包含main().cpp文件。

1.       define的保護

所有頭文件都應該使用#define防止頭文件被多重包含(multiple inclusion),命名格式當是:<PROJECT>_<PATH>_<FILE>_H_

爲保證唯一性,頭文件的命名應基於其所在項目源代碼樹的全路徑。例如,項目foo中的頭文件foo/src/bar/baz.h按如下方式保護:

#ifndef FOO_BAR_BAZ_H_
#define FOO_BAR_BAZ_H_
...
#endif // FOO_BAR_BAZ_H_

2.       頭文件依賴

使用前置聲明(forwarddeclarations)儘量減少.h文件中#include的數量。

3.       內聯函數

只有當函數只有10行甚至更少時纔會將其定義爲內聯函數(inline function)。

4.       -inl.h文件

複雜的內聯函數的定義,應放在後綴名爲-inl.h的頭文件中。

5.       函數參數順序

定義函數時,參數順序爲:輸入參數在前,輸出參數在後。

int function( const int&inut, int * output);

這一點並不是必須遵循的規則,輸入/輸出兩用參數(通常是類/結構體變量)混在其中,會使得規則難以遵循。

6.       包含文件的名稱及次序

將包含次序標準化可增強可讀性、避免隱藏依賴(hidden dependencies,譯者注:隱藏依賴主要是指包含的文件中編譯時),次序如下:cpp文件對應的.h文件、C庫、C++庫、其他庫的.h、項目內的.h

項目內頭文件應按照項目源代碼目錄樹結構排列,並且避免使用UNIX文件路徑.(當前目錄)和..(父目錄)。例如,google-awesome-project/src/base/logging.h應像這樣被包含:

#include"base/logging.h"

相同目錄下頭文件按字母序。

舉例來說,google-awesome-project/src/foo/internal/fooserver.cpp的包含次序如下:

#include"foo/public/fooserver.h"  // 優先位置

#include <sys/types.h>
#include <unistd.h>

#include <hash_map>
#include <vector>

#include"base/basictypes.h"
#include "base/commandlineflags.h"
#include "foo/public/bar.h"

 

 

 

 

 

 

 

 

 

二、       作用域

1.       非成員函數、靜態成員函數和全局函數

使用命名空間中的非成員函數或靜態成員函數,儘量不要使用全局函數。

2.       局部變量

函數變量使用統一入口和出口。

int function() {

    char *a= NULL;

const size_t size =10;

 a = new char[size];

if (NULL == a) {

gotoclearup:

}

cleanup:

      if (a != NULL) {

           delete []a;

       }

}

3.       全局變量

class類型的全局變量是被禁止的,內建類型的全局變量是允許的,當然多線程代碼中非常數全局變量也是被禁止的。永遠不要使用函數返回值初始化全局變量。靜態成員變量視作全局變量,所以,也不能是class類型!

三、      

1.       構造函數(Constructor)的職責

構造函數中只進行那些沒有實際意義的初始化,使用Init()方法集中初始化爲有意義的數據。

2.       默認構造函數(Default Constructors

如果一個類定義了若干成員變量又沒有其他構造函數,需要定義一個默認構造函數,否則編譯器將自動生產默認構造函數。

3.       明確的構造函數(Explicit Constructors

對單參數構造函數使用C++關鍵字explicitexplicit 可以有效得防止構造函數的隱式轉換帶來的錯誤或者誤解

class String {

      String ( int n ); //本意是預先分配n個字節給字符串

String ( const char* p ); // C風格的字符串p作爲初始化值

//…

}

下面兩種寫法比較正常:

String s2 ( 10);   //OK 分配10個字節的空字符串

String s3 =String ( 10 ); //OK 分配10個字節的空字符串

 

下面兩種寫法就比較疑惑了:

String s4 =10; //編譯通過,也是分配10個字節的空字符串

String s5 =‘a’; //編譯通過,分配int‘a’)個字節的空字符串

 

s4 s5 分別把一個int型和char型,隱式轉換成了分配若干字節的空字符串,容易令人誤解。

爲了避免這種錯誤的發生,我們可以聲明顯示的轉換,使用explicit 關鍵字:

class String {

      explicit String ( int n ); //本意是預先分配n個字節給字符串

String ( constchar* p ); // C風格的字符串p作爲初始化值

//…

}

加上explicit就抑制了String( int n )的隱式轉換,

 

下面兩種寫法仍然正確:

String s2 ( 10);   //OK 分配10個字節的空字符串

String s3 =String ( 10 ); //OK 分配10個字節的空字符串

 

下面兩種寫法就不允許了:

String s4 =10; //編譯不通過,不允許隱式的轉換

String s5 =‘a’; //編譯不通過,不允許隱式的轉換

4.       拷貝構造函數(Copy Constructors

僅在代碼中需要拷貝一個類對象的時候使用拷貝構造函數;不需要拷貝時應使用DISALLOW_COPY_AND_ASSIGN

// 禁止使用拷貝構造函數和賦值操作的宏
//
應在類的private:中使用
#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
  TypeName(const TypeName&);               \
  void operator=(const TypeName&)

class Foo {
public:
 
Foo(int f);
  ~Foo();

private:
 
DISALLOW_COPY_AND_ASSIGN(Foo);
};

如上所述,絕大多數情況下都應使用DISALLOW_COPY_AND_ASSIGN,如果類確實需要可拷貝,應在該類的頭文件中說明原由,並適當定義拷貝構造函數和賦值操作,注意在operator=中檢測自賦值(self-assignment)情況。

在將類作爲STL容器值得時候,你可能有使類可拷貝的衝動。類似情況下,真正該做的是使用指針指向STL容器中的對象,可以考慮使用std::tr1::shared_ptr

5.       結構體和類(Structs vs. Classes

僅當只有數據時使用struct,其它一概使用class

6.       繼承(Inheritance

使用組合通常比使用繼承更適宜,如果使用繼承的話,只使用公共繼承。

7.       接口(Interface

接口是指滿足特定條件的類,這些類以Interface爲後綴。

定義:當一個類滿足以下要求時,稱之爲純接口:

1) 只有純虛函數("=0")和靜態函數(下文提到的析構函數除外);

2) 沒有非靜態數據成員;

3) 沒有定義任何構造函數。如

果有,也不含參數,並且爲protected

4) 如果是子類,也只能繼承滿足上述條件並以Interface爲後綴的類。

結論:。只有在滿足上述需要時,類才以Interface結尾,但反過來,滿足上述需要的類未必一定以Interface結尾。

8.       操作符重載(Operator Overloading

除少數特定環境外,不要重載操作符。

有些STL算法確實需要重載operator==時可以這麼做,不要忘了提供文檔說明原因。

9.       存取控制(Access Control

將數據成員私有化,並提供相關存取函數,如定義變量foo_及取值函數foo()、賦值函數set_foo()。存取函數的定義一般內聯在頭文件中。

10.  聲明次序(Declaration Order

在類中使用特定的聲明次序:public:private:之前,成員函數在數據成員(變量)前。

定義次序如下:public:protected:private:,如果那一塊沒有,直接忽略即可。

每一塊中,聲明次序一般如下:

1) typedefsenums

2) 常量;

3) 構造函數;

4) 析構函數;

5) 成員函數,含靜態成員函數;

6) 數據成員,含靜態數據成員。

DISALLOW_COPY_AND_ASSIGN置於private:塊之後,作爲類的最後部分。參考拷貝構造函數

.cpp文件中函數的定義應儘可能和聲明次序一致。

11.  編寫短小函數(Write Short Functions

傾向於選擇短小、凝練的函數,以不超過40行爲宜。

四、       其他C++特性

1.       引用參數(Reference Arguments

所有按引用傳遞的參數必須加上const,map除外。

2.       函數重載(Function Overloading

僅在輸入參數類型不同、功能相同時使用重載函數(含構造函數),不要使用函數重載模仿缺省函數參數。

3.       缺省參數(Default Arguments

可以使用缺省函數參數。

4.       友元(Friends

允許合理使用友元類及友元函數。

5.       異常(Exceptions

不要使用C++異常。

6.       類型轉換(Casting

使用static_cast<>()C++的類型轉換,不要使用int y = (int)xinty = int(x);

7.       前置自增和自減(Preincrement andPredecrement

結論:對簡單數值(非對象)來說,兩種都無所謂,對迭代器和模板類型來說,要使用前置自增(自減)。

8.       const的使用(Use of const

在任何可以使用的情況下都要使用const,map除外

9.       整型(Integer Types

C++內建整型中,唯一用到的是int,如果程序中需要不同大小的變量,可以使用<stdint.h>中的精確寬度(precise-width)的整型,如int16_t

10.  預處理宏(Preprocessor Macros

使用宏時要謹慎,儘量以內聯函數、枚舉和常量代替之。

下面給出的用法模式可以避免一些使用宏的問題,供使用宏時參考:

1) 不要在.h文件中定義宏;

2) 使用前正確#define,使用後正確#undef

3) 不要只是對已經存在的宏使用#undef,選擇一個不會衝突的名稱;

4) 不使用會導致不穩定的C++構造的宏,至少文檔說明其行爲。

如下所示,類Test可能會構造失敗。

Class Test {

public

       Test() {

              _p = new char[10];

       }

private:

       char *_p;

};

#define  NEW_TEST new Test()

Test * p = NEW_TEST;

11.  0NULL0 and NULL

整數用0,實數用0.0,指針用NULL,字符(串)用'\0'

12.  sizeofsizeof

儘可能用sizeof(varname)代替sizeof(type)。使用sizeof(varname)是因爲當變量類型改變時代碼自動同步,有些情況下sizeof(type)或許有意義,還是要儘量避免,如果變量類型改變的話不能同步。

Struct data;

memset(&data, 0, sizeof(data));

memset(&data, 0, sizeof(Struct));

13.  Boost庫(Boost

只使用Boost中被認可的庫,推薦只是用智能指針相關的庫。

五、       命名約定

1.       通用命名規則(General Naming Rules

函數命名、變量命名、文件命名應具有描述性,不要過度縮寫,類型和變量應該是名詞,函數名可以用命令性動詞。

如何命名

儘可能給出描述性名稱,不要節約空間:

int num_errors;                  // Good.

int num_completed_connections;   // Good.

醜陋的命名使用模糊的縮寫或隨意的字符:

int n;                           // Bad -meaningless.

int nerr;                        // Bad - ambiguousabbreviation.

int n_comp_conns;                // Bad - ambiguousabbreviation.

類型和變量名一般爲名詞:如FileOpenernum_errors。函數名通常是指令性的,如OpenFile()set_num_errors(),訪問函數需要描述的更細緻,要與其訪問的變量相吻合。

縮寫

除非放到項目外也非常明瞭,否則不要使用縮寫,例如:

// Good

// These show proper names with no abbreviations.

int num_dns_connections;  // Most people know what "DNS"stands for.

int price_count_reader;   // OK, price count. Makes sense.

 

// Bad!

// Abbreviations can be confusing or ambiguousoutside a small group.

int wgc_connections; // Only your group knows what this stands for.

int pc_reader;       // Lots of things can be abbreviated "pc".

2.       文件命名(File Names

文件名要全部小寫,用下劃線(_)相連。

my_useful_class.cpp

C++文件以.cpp結尾,頭文件以.h結尾。

不要使用已經存在於/usr/include下的文件名(譯者注,對UNIXLinux等系統而言),如db.h

通常,儘量讓文件名更加明確,http_server_logs.h就比logs.h要好,定義類時文件名一般成對出現,如foo_bar.hfoo_bar.cpp,對應類FooBar

內聯函數必須放在.h文件中,如果內聯函數比較短,就直接放在.h中。如果代碼比較長,可以放到以-inl.h結尾的文件中。對於包含大量內聯代碼的類,可以有三個文件:

url_table.h     // The class declaration.

url_table.cpp    // The class definition.

url_table-inl.h // Inline functions that include lots of code.

3.       類型命名(Type Names

類型命名每個單詞以大寫字母開頭,不包含下劃線:MyExcitingClassMyExcitingEnum

所有類型命名——類、結構體、類型定義(typedef)、枚舉——使用相同約定,例如:

// classes and structs

class UrlTable { ...

class UrlTableTester { ...

struct UrlTableProperties { ...

 

// typedefs

typedef hash_map<UrlTableProperties *, string>PropertiesMap;

 

// enums

enum UrlTableErrors { ...

4.       變量命名(Variable Names

變量名一律小寫,單詞間以下劃線相連,類的成員變量以下劃線開頭,如my_exciting_local_variable_my_exciting_member_variable。不用m_開頭,也不用_結尾。

普通變量命名

string table_name; // OK - uses underscore.

stringtableName;   // Bad - mixed case.

類數據成員

結構體的數據成員可以和普通變量一樣,不用像類那樣接下劃線:

struct UrlTableProperties {

  string name;

  intnum_entries;

}

全局變量

對全局變量沒有特別要求,少用就好,可以以g_或其他易與局部變量區分的標誌爲前綴。

5.       常量命名(Constant Names

在名稱前加kkDaysInAWeek。所有編譯時常量(無論是局部的、全局的還是類中的)和其他變量保持些許區別,k後接大寫字母開頭的單詞:

const int kDaysInAWeek = 7;

6.       函數命名(Function Names

函數大小寫混合,存取函數則要求與變量名匹配:myExcitingFunction()myExcitingMethod()

普通函數

函數名以小寫字母開頭,每個單詞首字母大寫,沒有下劃線:

addTableEntry()

deleteUrl()

存取函數

存取函數要與存取的變量名匹配,這兒摘錄一個擁有實例變量num_entries_的類:

class MyClass {

public:

  ...

    int numEntries() const { return _num_entries;}

    void SetNumEntries(int num_entries) { _num_entries= num_entries; }

 

private:

  int _num_entries;

};

其他短小的內聯函數名也可以使用小寫字母,例如,在循環中調用這樣的函數甚至都不需要緩存其值,小寫命名就可以接受。

7.       命名空間(Namespace Names

命名空間的名稱是全小寫的,其命名基於項目名稱和目錄結構:google_awesome_project

8.       枚舉命名(Enumerator Names

枚舉值應全部大寫,單詞間以下劃線相連:MY_EXCITING_ENUM_VALUE

枚舉名稱屬於類型,因此大小寫混合:UrlTableErrors

enum UrlTableErrors {

  OK = 0,

 ERROR_OUT_OF_MEMORY,

 ERROR_MALFORMED_INPUT,

};

9.       宏命名(Macro Names

通常是不使用宏的,如果絕對要用,其命名像枚舉命名一樣全部大寫、使用下劃線:

#define ROUND(x) ...

#define PI_ROUNDED 3.0

MY_EXCITING_ENUM_VALUE

六、       註釋

1.       註釋風格(Comment Style

使用//或/* */,統一就好。

//或/* */都可以,//只是用的更加廣泛,在如何註釋和註釋風格上確保統一

行註釋

比較隱晦的地方要在行尾加入註釋,可以在代碼之後空兩格加行尾註釋,如:

// If we have enough memory,mmap the data portion too.

mmap_budget =max<int64>(0, mmap_budget - index_->length());

if (mmap_budget >=data_size_ && !MmapData(mmap_chunk_bytes, mlock))

  return; // Error already logged.

注意,有兩塊註釋描述這段代碼,當函數返回時註釋提及錯誤已經被記入日誌。

前後相鄰幾行都有註釋,可以適當調整使之可讀性更好:

...

DoSomething();                  // Comment here so thecomments line up.

DoSomethingElseThatIsLonger();  // Comment here so there are two spacesbetween

                                // the code andthe comment.

...

NULLtrue/false123……

向函數傳入、布爾值或整數時,要註釋說明含義,或使用常量讓代碼望文知意,比較一下:

bool success =CalculateSomething(interesting_value,

                                  10,

                                  false,

                                  NULL);  // What are these arguments??

和:

bool success =CalculateSomething(interesting_value,

                                  10,    // Default base value.

                                  false,  // Not the first time we're calling this.

                                  NULL);  // No callback.

使用常量或描述性變量:

const int kDefaultBaseValue =10;

const bool kFirstTimeCalling =false;

Callback *null_callback =NULL;

bool success =CalculateSomething(interesting_value,

                                 kDefaultBaseValue,

                                 kFirstTimeCalling,

                                 null_callback);

2.       TODO註釋(TODO Comments

對那些臨時的、短期的解決方案,或已經夠好但並不完美的代碼使用TODO註釋。

這樣的註釋要使用全大寫的字符串TODO,後面括號(parentheses)里加上你的大名、郵件地址等,還可以加上冒號(colon):目的是可以根據統一的TODO格式進行查找:

// TODO([email protected]): Use a"*" here for concatenation operator.

// TODO(Zeke) change this touse relations.

如果加上是爲了在將來某一天做某事,可以加上一個特定的時間("Fix by November2005")或事件("Removethis code when all clients can handle XML responses.")。

七、       格式

1.       行長度(Line Length

每一行代碼字符數不超過80

2.       ASCII字符(Non-ASCII Characters

儘量不使用非ASCII字符,使用時必須使用UTF-8格式。

3.       空格縮進

只使用空格,每次縮進4個空格。

4.       函數聲明與定義(Function Declarations andDefinitions

返回類型和函數名在同一行,合適的話,參數也放在同一行。

ReturnType ClassName::FunctionName(Type par_name1,Type par_name2) {

 DoSomething();

  ...

}

如果同一行文本較多,容不下所有參數:

ReturnType ClassName::ReallyLongFunctionName(Typepar_name1,

                                            Type par_name2,

                                            Type par_name3) {

 DoSomething();

  ...

}

甚至連第一個參數都放不下:

ReturnTypeLongClassName::ReallyReallyReallyLongFunctionName(

    Typepar_name1,  // 4 space indent

    Typepar_name2,

    Typepar_name3) {

 DoSomething();  // 2 space indent

  ...

}

注意以下幾點:

1) 返回值總是和函數名在同一行;

2) 左圓括號(openparenthesis)總是和函數名在同一行;

3) 函數名和左圓括號間沒有空格;

4) 圓括號與參數間沒有空格;

5) 左大括號(open curlybrace)總在最後一個參數同一行的末尾處;

6) 右大括號(closecurly brace)總是單獨位於函數最後一行;

7) 右圓括號(closeparenthesis)和左大括號間總是有一個空格;

8) 函數聲明和實現處的所有形參名稱必須保持一致;

9) 所有形參應儘可能對齊;

如果函數爲const的,關鍵字const應與最後一個參數位於同一行。

// Everything in this function signature fits on asingle line

ReturnType FunctionName(Type par) const {

  ...

}

 

// This function signature requires multiple lines,but

// the const keyword is on the line with the lastparameter.

ReturnType ReallyLongFunctionName(Type par1,

                                  Type par2)const {

  ...

}

如果有些參數沒有用到,在函數定義處將參數名註釋起來:

// Always have named parameters in interfaces.

class Shape {

public:

    virtual void Rotate(double radians) = 0;

}

 

// Always have named parameters in the declaration.

class Circle : public Shape {

public:

    virtual void Rotate(double radians);

}

 

// Comment out unused named parameters indefinitions.

void Circle::Rotate(double /*radians*/) {}

// Bad - if someone wants to implement later, it'snot clear what the

// variable means.

void Circle::Rotate(double) {}

5.       函數調用(Function Calls

儘量放在同一行,否則,將實參封裝在圓括號中。

bool retval = DoSomething(argument1, argument2,argument3);

如果同一行放不下,可斷爲多行,後面每一行都和第一個實參對齊,左圓括號後和右圓括號前不要留空格:

bool retval =DoSomething(averyveryveryverylongargument1,

                          argument2,argument3);

如果函數參數比較多,可以出於可讀性的考慮每行只放一個參數:

bool retval = DoSomething(argument1,

                          argument2,

                          argument3,

                          argument4);

 

如果函數名太長,以至於超過行最大長度,可以將所有參數獨立成行:

if (...) {

  ...

  ...

  if (...) {

   DoSomethingThatRequiresALongFunctionName(

       very_long_argument1,  // 4 spaceindent

       argument2,

       argument3,

       argument4);

  }

6.       條件語句(Conditionals

不在圓括號中添加空格,關鍵字else另起一行,所有分支用大括號包含起來。

if (condition) { // no spaces inside parentheses

  ...  // 2 space indent.

} else {  //The else goes on the same line as the closing brace.

  ...

}

注意所有情況下if和左圓括號間有個空格,右圓括號和左大括號間也要有個空格:

if(condition)    // Bad - space missing after IF.

if (condition){  // Bad - space missing before {.

if(condition){   // Doubly bad.

if (condition) { // Good - proper space after IF and before {.

7.       循環和開關選擇語句(Loops and SwitchStatements

switch語句可以使用大括號分塊;空循環體應使用{}continuecase塊可以使用大括號也可以不用。

switch (var) {

  case 0:{  // 2 space indent

    ...      // 4 space indent

    break;

  }

  case 1: {

    ...

    break;

  }

  default: {

   assert(false);

  }

}

空循環體應使用{}continue,而不是一個簡單的分號:

while (condition) {

  // Repeattest until it returns false.

}

for (int i = 0; i < kSomeNumber; ++i) {}  // Good - empty body.

while (condition) continue;  // Good - continue indicates no logic.

while (condition); // Bad - looks like part of do/while loop.

8.       指針和引用表達式(Pointers and ReferenceExpressions

句點(.)或箭頭(->)前後不要有空格,指針/地址操作符(*、&)後不要有空格。

下面是指針和引用表達式的正確範例:

x = *p;

p = &x;

x = r.y;

x = r->y;

注意:

1) 在訪問成員時,句點或箭頭前後沒有空格;

2) 指針操作符*&後沒有空格。

在聲明指針變量或參數時,星號與變量名緊挨:

// These are fine, space preceding.

char *c;

const string &str;

 

// These are fine, space following.

char* c;    //but remember to do "char* c, *d, *e, ...;"!

const string& str;

char * c;  //Bad - spaces on both sides of *

const string & str;  // Bad - spaces on both sides of &

9.       布爾表達式(Boolean Expressions

如果一個布爾表達式超過標準行寬,需要斷行,邏輯操作符總位於行尾:

if (this_one_thing > this_other_thing &&

   a_third_thing == a_fourth_thing &&

   yet_another & last_one) {

  ...

}

兩個邏輯與(&&)操作符都位於行尾,可以考慮額外插入圓括號,合理使用的話對增強可讀性是很有幫助的。

10.  函數返回值(Return Values

return表達式中不要使用圓括號。

return x;  //not return(x);

11.  變量及數組初始化(Variable and ArrayInitialization

選擇=

int x = 3;

string name = "Some Name";

12.  預處理指令(Preprocessor Directives

預處理指令不要縮進,即使它位於縮進代碼塊中,指令也應從行首開始。

// Good - directives at beginning of line

  if(lopsided_score) {

#if DISASTER_PENDING      // Correct -- Starts at beginning of line

   DropEverything();

#endif

   BackToNormal();

  }

// Bad - indented directives

  if(lopsided_score) {

    #if DISASTER_PENDING  // Wrong! The "#if" should be at beginning of line

   DropEverything();

   #endif                //Wrong!  Do not indent "#endif"

   BackToNormal();

  }

13.  類格式(Class Format

聲明屬性依次序是public:protected:private:,不縮進。

類聲明(對類註釋不瞭解的話,參考第六篇中的類註釋一節)的基本格式如下:

class MyClass : public OtherClass {

public::     // Note the 1 space indent!

    MyClass(); // Regular 2 space indent.

    explicit MyClass(int var);

    ~MyClass() {}

 

    void SomeFunction();

    void SomeFunctionThatDoesNothing() {

  }

 

    void setSomeVar(int var) { _some_var = var; }

    int someVar() const { return _some_var; }

 

private::

    bool SomeInternalFunction();

 

    int _some_var;

    int _some_other_var;

    DISALLOW_COPY_AND_ASSIGN(MyClass);

};

注意:

1) 所以基類名應在80列限制下儘量與子類名放在同一行;

2) 關鍵詞public:、protected:private:不縮進

3) 除第一個關鍵詞外,其他關鍵詞前空一行,如果類比較小的話也可以不空;

4) 這些關鍵詞後不要空行;

5) public放在最前面,然後是protectedprivate

14.  初始化列表(Initializer Lists

構造函數初始化列表放在同一行或按四格縮進並排幾行。

兩種可以接受的初始化列表格式:

// When it all fits on one line:

MyClass::MyClass(int var) : some_var_(var),some_other_var_(var + 1) {

// When it requires multiple lines, indent 4 spaces,putting the colon on

// the first initializer line:

MyClass::MyClass(int var)

    :some_var_(var),             // 4 spaceindent

     some_other_var_(var + 1) {  //lined up

  ...

 DoSomething();

  ...

}

15.  命名空間格式化(Namespace Formatting

命名空間內容不縮進。

namespace {

 

void foo() { // Correct.  No extra indentationwithin namespace.

  ...

}

 

// namespace

16.  水平留白(Horizontal Whitespace

水平留白的使用因地制宜。不要在行尾添加無謂的留白。

普通

void f(bool b) { // Open braces should always have a space before them.

  ...

int i = 0;  //Semicolons usually have no space before them.

int x[] = { 0 }; // Spaces inside braces for array initialization are

int x[] = {0};   // optional.  If you use them, putthem on both sides!

// Spaces around the colon in inheritance andinitializer lists.

class Foo : public Bar {

 public:

  // Forinline function implementations, put spaces between the braces

  // and theimplementation itself.

  Foo(int b) :Bar(), baz_(b) {}  // No spaces insideempty braces.

  void Reset(){ baz_ = 0; }  // Spaces separatingbraces from implementation.

  ...

循環和條件語句

if (b) {         // Space after the keyword in conditions and loops.

} else {         // Spaces around else.

}

while (test) {}  // There is usually no space inside parentheses.

switch (i) {

for (int i = 0; i < 5; ++i) {

switch ( i ) {   // Loops and conditions may have spaces inside

if ( test ) {    // parentheses, but this is rare. Be consistent.

for ( int i = 0; i < 5; ++i ) {

for ( ; i < 5 ; ++i) {  // For loops always have a space after the

  ...                   // semicolon, and may have aspace before the

                        // semicolon.

switch (i) {

  case 1:         // No space before colon in a switchcase.

    ...

  case 2:break;  // Use a space after a colon ifthere's code after it.

操作符

x = 0;             // Assignment operators always have spaces around them.

x = -5;            // No spaces separating unary operators and their

++x;               // arguments.

if (x && !y)

  ...

v = w * x + y / z; // Binary operators usually have spaces around them,

v = w*x + y/z;     // but it's okay to remove spaces around factors.

v = w * (x + z);   // Parentheses should have no spaces inside them.

 

模板和轉換

vector<string> x;           // No spaces inside the angle

y = static_cast<char*>(x);  // brackets (< and >), before

                            // <, or between>( in a cast.

vector<char *> x;           // Spaces between type and pointerare

                            // okay, but beconsistent.

set<list<string> > x;       // C++ requires a space in > >.

set< list<string> > x;      // You may optionally make use

                            // symmetric spacing in < <.

17.  垂直留白(Vertical Whitespace

垂直留白越少越好,不要在兩個函數定義之間空超過2行,函數體頭、尾不要有空行,函數體中也不要隨意添加空行。

函數頭、尾不要有空行:

void Function() {

 

  //Unnecessary blank lines before and after

 

}

代碼塊頭、尾不要有空行:

while (condition) {

  //Unnecessary blank line after

 

}

if (condition) {

 

  //Unnecessary blank line before

}

if-else塊之間空一行還可以接受:

if (condition) {

  // Somelines of code too small to move to another function,

  // followedby a blank line.

 

} else {

  // Anotherblock of code

}

發佈了75 篇原創文章 · 獲贊 17 · 訪問量 17萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章