Google Style 學(xué)習(xí)


頭文件

  • 頭文件避免多重包含。#ifndef PROJ_PATH_FILE_H_
  • 能用前置聲明就不要使用#include。
  • 函數(shù)的參數(shù)順序:輸入?yún)?shù),輸出參數(shù)。

作用域

  • 不要使用using
  • 命名空間不需縮進(jìn)。
  • .c中可以使用using.h中必須在函數(shù)、方法、類內(nèi)部使用。
  • 非成員函數(shù)、靜態(tài)成員函數(shù)、全局函數(shù)盡量放到命名空間中。
  • 局部變量聲明的時(shí)候賦值。在離第一次使用盡可能近的地方聲明。
  • 可在while循環(huán)中聲明變量限制其作用域。
  • 注意有時(shí)需在循環(huán)外聲明變量,比如類的對(duì)象,在循環(huán)內(nèi)聲明需要循環(huán)調(diào)用構(gòu)造函數(shù)和析構(gòu)函數(shù)。

  • 構(gòu)造函數(shù)只進(jìn)行一些非重要內(nèi)容的初始化,因?yàn)槿绻僮魇?huì)造成對(duì)象初始化失敗,進(jìn)入不確定狀態(tài)。
    可能的話,使用Init()方法集中初始化有意義的數(shù)據(jù)。
  • 如果類有很多個(gè)變量,最好設(shè)置默認(rèn)構(gòu)造函數(shù),否則編譯器可能會(huì)生成一個(gè)很糟糕的構(gòu)造函數(shù)。
  • 對(duì)單個(gè)參數(shù)的構(gòu)造函數(shù)使用explicit關(guān)鍵字,防止默認(rèn)強(qiáng)制類型轉(zhuǎn)換。
  • 一般如果沒(méi)有拷貝構(gòu)造函數(shù),編譯器會(huì)自動(dòng)聲明拷貝構(gòu)造函數(shù),而且是public的。
    如果是單例模式需要禁止拷貝,則可以在private中聲明但不定義拷貝構(gòu)造函數(shù),這樣當(dāng)試圖使用它們時(shí)編譯器將報(bào)錯(cuò)。用宏來(lái)描述:
#define DISALLOW_COPY_AND_ASSIGN(TypeName) \\
            TypeName(const TypeName&); \\
            void operator=(const TypeName&)
         private:
        DISALLOW_COPY_AND_ASSIGN(Foo);
  • 當(dāng)只有數(shù)據(jù)時(shí)使用struct,其他一概用class。struct只可以有構(gòu)造函數(shù),析構(gòu)函數(shù),Initialize(),Reset()Validate()。
  • 組合 > 實(shí)現(xiàn)繼承 > 接口繼承 > 私有繼承,子類重載的虛函數(shù)也要聲明virtual關(guān)鍵字。
  • 使用組合(composition)通常比繼承更合理。如果需要類繼承,使用public繼承。
  • 盡量做到is-a繼承,在has-a繼承時(shí)盡量使用composition。
  • 數(shù)據(jù)成員在任何情況下應(yīng)該都只是私有的。
  • 當(dāng)定義一個(gè)虛函數(shù)時(shí),明確聲明其為virtual,使得代碼閱讀者在檢查基類的時(shí)候易于判斷。
    如果類有虛函數(shù),則析構(gòu)函數(shù)最好也聲明為virtual。
  • 真正需要用到多重實(shí)現(xiàn)繼承的情況少之又少。
    只在以下情況我們才允許多重繼承:最多只有一個(gè)基類是非抽象類,其它基類都是以Interface為后綴的純接口類。接口類類名以Interface為后綴。
  • 為降低復(fù)雜性,盡量不重載操作符。
  • 在類中使用特定的聲明順序:public:在 private:之前,成員函數(shù)在數(shù)據(jù)成員(變量)前。順序:
  • typedefs和枚舉
  • 常量->構(gòu)造函數(shù)
  • 析構(gòu)函數(shù)
  • 成員函數(shù), 含靜態(tài)成員函數(shù)
  • 數(shù)據(jù)成員, 含靜態(tài)數(shù)據(jù)成員
  • 將所有數(shù)據(jù)成員聲明為 private, 并根據(jù)需要提供相應(yīng)的存取函數(shù)。存取函數(shù)一般內(nèi)聯(lián)在頭文件中。
  • 傾向編寫(xiě)簡(jiǎn)短, 凝練的函數(shù)。如果函數(shù)超過(guò) 40 行,可以思索一下能不能在不影響程序結(jié)構(gòu)的前提下對(duì)其進(jìn)行分割。

其他 C++ 特性

  • 所有按引用傳遞參數(shù)必須加上const。函數(shù)中非輸出參數(shù)最好都加上const
  • 在任何可能的地方加上const。
  • 如果你想重載一個(gè)函數(shù),考慮讓函數(shù)名包含參數(shù)信息,例如,使用 AppendString(),AppendInt()而不是Append()。
  • 盡可能少的將函數(shù)的參數(shù)設(shè)置默認(rèn)值。
  • 減少使用變長(zhǎng)數(shù)組。
  • 允許合理的友元類和友元函數(shù)。
  • 類型轉(zhuǎn)換時(shí)需要明確指明static_castconst_cast,reinterpret_cast,dynamic_cast
  • 只在打印日志的時(shí)候使用流。流最大的優(yōu)勢(shì)是在輸出時(shí)不需要關(guān)心打印對(duì)象的類型。
    這是一個(gè)亮點(diǎn),同時(shí)也是一個(gè)不足:你很容易用錯(cuò)類型,而編譯器不會(huì)報(bào)警。
    使用流時(shí)容易造成的這類錯(cuò)誤:
cout << this;   // Prints the address
 cout << *this;  // Prints the contents
  • 對(duì)于迭代器和其他模板對(duì)象使用前置的自增自減。
  • 使用宏時(shí)要非常謹(jǐn)慎,盡量以內(nèi)聯(lián)函數(shù)、枚舉和常量代替之。
    不要在 .h 文件中定義宏。
    在馬上要使用時(shí)才進(jìn)行 #define。使用后要立即 #undef。
  • 整數(shù)用 0,實(shí)數(shù)用0.0,指針用 NULL,字符(串)用'\\0'。
  • 盡可能用sizeof(varname)代替sizeof(type),代碼中變量類型改變后可以進(jìn)行自動(dòng)更新。

命名約定

  • 盡可能給出描述性的名稱。不要節(jié)約行空間,讓別人很快理解你的代碼更重要。
 int num_errors;                  // Good.
 int num_completed_connections;   // Good
  • 類型和變量名一般為名詞:如FileOpener,num_errors
    函數(shù)名通常是指令性的,如OpenFile(),set_num_errors()。
    取值函數(shù)是個(gè)特例,函數(shù)名和它要取值的變量同名。
  • 除非該縮寫(xiě)在其它地方都非常普遍,否則不要使用。永遠(yuǎn)不要用省略字母的縮寫(xiě)。
 int error_count;  // Good
 int error_cnt;    // Bad
  • 文件名要全部小寫(xiě),可以包含下劃線(_)或連字符 (-)。可接受的文件命名:my_useful_class.cc、my-useful-class.cc、yusefulclass.cc,通常應(yīng)盡量讓文件名更加明確。
  • 類型名稱的每個(gè)單詞首字母均大寫(xiě),不包含下劃線,大駝峰法。
    所有類型命名:類、結(jié)構(gòu)體、類型定義(typedef)、枚舉->均使用相同約定。
  • 變量名一律小寫(xiě),單詞之間用下劃線連接。類的成員變量以下劃線結(jié)尾。
    結(jié)構(gòu)體的數(shù)據(jù)成員可以和普通變量一樣,不用像類那樣接下劃線。
  • 常量名稱前加k,如:const int kDaysInAWeek = 7;
  • 常規(guī)函數(shù)的函數(shù)名的每個(gè)單詞首字母大寫(xiě),沒(méi)有下劃線。
  • 取值和設(shè)值函數(shù)要與存取的變量名匹配。
  • int num_entries_;
  • int num_entries() const { return num_entries_; }
  • 枚舉內(nèi)數(shù)據(jù)的命名應(yīng)當(dāng)和常量或宏一致:kEnumName或是ENUM_NAME。
  • 宏命名:全大小,下劃線。如#define PI_ROUNDED 3.0

注釋

  • 注釋要言簡(jiǎn)意賅, 不要拖沓冗余, 復(fù)雜的東西簡(jiǎn)單化和簡(jiǎn)單的東西復(fù)雜化都是要被鄙視的。
  • 注釋固然很重要, 但最好的代碼本身應(yīng)該是自文檔化。有意義的類型名和變量名,要遠(yuǎn)勝過(guò)要用注釋解釋的含糊不清的名字。
  • 在每一個(gè)文件開(kāi)頭加入版權(quán)公告,然后是文件內(nèi)容描述。
    每個(gè)文件都應(yīng)該包含以下項(xiàng), 依次是:
  • 版權(quán)聲明 (比如,Copyright 2008 Google Inc.)
  • 許可證. 為項(xiàng)目選擇合適的許可證版本 (比如,Apache 2.0, BSD, LGPL, GPL)
  • 作者: 標(biāo)識(shí)文件的原始作者.
  • 通常,.h文件要對(duì)所聲明的類的功能和用法作簡(jiǎn)單說(shuō)明,.cc 文件通常包含了更多的實(shí)現(xiàn)細(xì)節(jié)或算法技巧討論。如果你感覺(jué)這些實(shí)現(xiàn)細(xì)節(jié)或算法技巧討論對(duì)于理解 .h 文件有幫助,可以該注釋挪到 .h,并在.cc中指出文檔在.h。
    不要簡(jiǎn)單的在.h.cc間復(fù)制注釋,這種偏離了注釋的實(shí)際意義。
  • 每個(gè)類的定義都要附帶一份注釋,描述類的功能和用法。
  • 對(duì)于代碼中巧妙的,晦澀的,有趣的,重要的地方加以注釋。
  • 比較隱晦的地方要在行尾空兩格進(jìn)行注釋。
  • 向函數(shù)傳入NULL, 布爾值或整數(shù)時(shí), 要注釋說(shuō)明含義, 或使用常量讓代碼望文知意:
 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);
  • 連續(xù)多行輸入需要對(duì)齊:
DoSomething();                  // Comment here so the comments line up.
DoSomethingElseThatIsLonger();  // Comment here so there are two spaces between
                                // the code and the comment.
{ // One space before comment when opening a new scope is allowed,
  // thus the comment lines up with the following comments and code.
  DoSomethingElse();  // Two spaces before line comments normally.
}
  • 注意永遠(yuǎn)不要用自然語(yǔ)言翻譯代碼作為注釋。
  • TODO注釋
// TODO(kl@gmail.com): Use a "*" here for concatenation operator.
// TODO(Zeke) change this to use relations.

如果加 TODO 是為了在 “將來(lái)某一天做某事”, 可以附上一個(gè)非常明確的時(shí)間 “Fix by November 2005”), 或者一個(gè)明確的事項(xiàng) (“Remove this code when all clients can handle XML responses.”)。

格式

  • 盡量不使用非 ASCII 字符, 使用時(shí)必須使用 UTF-8 編碼。
  • 返回類型和函數(shù)名在同一行, 參數(shù)也盡量放在同一行。
    函數(shù)看上去像這樣:
ReturnType ClassName::FunctionName(Type par_name1, Type par_name2) {
    DoSomething();
    ...
}

如果同一行文本太多, 放不下所有參數(shù):

ReturnType ClassName::ReallyLongFunctionName(Type par_name1,
                                             Type par_name2,
                                             Type par_name3) {
    DoSomething();
    ...
}

甚至連第一個(gè)參數(shù)都放不下:

ReturnType LongClassName::ReallyReallyReallyLongFunctionName(
        Type par_name1,  // 4 space indent
        Type par_name2,
        Type par_name3) {
    DoSomething();  // 2 space indent
    ...
}
  • 注意以下幾點(diǎn):
    • 返回值總是和函數(shù)名在同一行;
    • 左圓括號(hào)總是和函數(shù)名在同一行;
    • 函數(shù)名和左圓括號(hào)間沒(méi)有空格;
    • 圓括號(hào)與參數(shù)間沒(méi)有空格;
    • 左大括號(hào)總在最后一個(gè)參數(shù)同一行的末尾處;
    • 右大括號(hào)總是單獨(dú)位于函數(shù)最后一行;
    • 右圓括號(hào)和左大括號(hào)間總是有一個(gè)空格;
    • 函數(shù)聲明和實(shí)現(xiàn)處的所有形參名稱必須保持一致;
    • 所有形參應(yīng)盡可能對(duì)齊;
    • 缺省縮進(jìn)為 2 個(gè)空格;
    • 換行后的參數(shù)保持 4 個(gè)空格的縮進(jìn);
  • 如果函數(shù)聲明成 const, 關(guān)鍵字const 應(yīng)與最后一個(gè)參數(shù)位于同一行:
// Everything in this function signature fits on a single line
ReturnType FunctionName(Type par) const {
  ...
}
// This function signature requires multiple lines, but
// the const keyword is on the line with the last parameter.
ReturnType ReallyLongFunctionName(Type par1,
                                  Type par2) const {
  ...
}
  • 如果有些參數(shù)沒(méi)有用到, 在函數(shù)定義處將參數(shù)名注釋起來(lái)。
// Comment out unused named parameters in definitions.
void Circle::Rotate(double /*radians*/) {}
  • 函數(shù)調(diào)用遵循如下形式:
bool retval = DoSomething(argument1, argument2, argument3);

如果同一行放不下, 可斷為多行, 后面每一行都和第一個(gè)實(shí)參對(duì)齊, 左圓括號(hào)后和右圓括號(hào)前不要留空格:

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

如果函數(shù)參數(shù)很多, 出于可讀性的考慮可以在每行只放一個(gè)參數(shù):

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

如果函數(shù)名非常長(zhǎng), 以至于超過(guò) 行最大長(zhǎng)度, 可以將所有參數(shù)獨(dú)立成行:

if (...) {
  ...
  ...
  if (...) {
    DoSomethingThatRequiresALongFunctionName(
        very_long_argument1,  // 4 space indent
        argument2,
        argument3,
        argument4);
  }
  • 條件語(yǔ)句,如if和左圓括號(hào)間都有個(gè)空格。右圓括號(hào)和左大括號(hào)之間也要有個(gè)空格。
  • switch語(yǔ)句:
switch (var) {
  case 0: {  // 2 space indent
    ...      // 4 space indent
    break;
  }
  case 1: {
    ...
    break;
  }
  default: {
    assert(false);
  }
}
  • 空循環(huán)體應(yīng)使用 {}continue, 而不是一個(gè)簡(jiǎn)單的分號(hào)。
while (condition) {
  // Repeat test until it returns false.
}
for (int i = 0; i < kSomeNumber; ++i) {}  // Good - empty body.
while (condition) continue;  // Good - continue indicates no logic.
Warning
while (condition);  // Bad - looks like part of do/while loop.
  • 指針和引用:句點(diǎn)或箭頭前后不要有空格. 指針/地址操作符 (*, &) 之后不能有空格。
  • 邏輯與 (&&) 操作符總位于行尾:
if (this_one_thing > this_other_thing &&
    a_third_thing == a_fourth_thing &&
    yet_another & last_one) {
  ...
}
  • return 表達(dá)式中不要用圓括號(hào)包圍。
  • 預(yù)處理指令不要縮進(jìn),從行首開(kāi)始。
    即使預(yù)處理指令位于縮進(jìn)代碼塊中, 指令也應(yīng)從行首開(kāi)始。
// Good - directives at beginning of line
  if (lopsided_score) {
#if DISASTER_PENDING      // Correct -- Starts at beginning of line
    DropEverything();
#endif
    BackToNormal();
  }
  • 訪問(wèn)控制塊的聲明依次序是 public:, protected:, private:, 每次縮進(jìn) 1 個(gè)空格。
  • 除第一個(gè)關(guān)鍵詞(一般是public)外, 其他關(guān)鍵詞前要空一行。這些關(guān)鍵詞后不要保留空行。
  • 名字空間內(nèi)容不縮進(jìn)。
  • 垂直留白越少越好。這不僅僅是規(guī)則而是原則問(wèn)題了: 不在萬(wàn)不得已, 不要使用空行,尤其是:
  • 兩個(gè)函數(shù)定義之間的空行不要超過(guò) 2 行, 函數(shù)體首尾不要留空行, 函數(shù)體中也不要隨意添加空行。
  • 基本原則是: 同一屏可以顯示的代碼越多,越容易理解程序的控制流。
  • 當(dāng)然,過(guò)于密集的代碼塊和過(guò)于疏松的代碼塊同樣難看, 取決于你的判斷. 但通常是垂直留白越少越好。

結(jié)束語(yǔ)

  • 運(yùn)用常識(shí)和判斷力,并保持一致。
  • 風(fēng)格指南的重點(diǎn)在于提供一個(gè)通用的編程規(guī)范, 這樣大家可以把精力集中在實(shí)現(xiàn)內(nèi)容而不是表現(xiàn)形式上。我們展示了全局的風(fēng)格規(guī)范, 但局部風(fēng)格也很重要。
  • 如果你在一個(gè)文件中新加的代碼和原有代碼風(fēng)格相去甚遠(yuǎn), 這就破壞了文件本身的整體美觀, 也影響閱讀, 所以要盡量避免。

參考閱讀

Google C++ 風(fēng)格指南 - 中文版
Google 開(kāi)源項(xiàng)目風(fēng)格指南

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容