在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

Google編程風(fēng)格指南(二)

C語(yǔ)言專(zhuān)家集中營(yíng) ? 來(lái)源:未知 ? 作者:李倩 ? 2018-09-27 18:01 ? 次閱讀

2. 作用域

2.1. 命名空間

Tip

鼓勵(lì)在.cc文件內(nèi)使用匿名命名空間或static聲明. 使用具名的命名空間時(shí), 其名稱(chēng)可基于項(xiàng)目名或相對(duì)路徑. 禁止使用 using 指示(using-directive)。禁止使用內(nèi)聯(lián)命名空間(inline namespace)。

定義:

命名空間將全局作用域細(xì)分為獨(dú)立的, 具名的作用域, 可有效防止全局作用域的命名沖突.

優(yōu)點(diǎn):

雖然類(lèi)已經(jīng)提供了(可嵌套的)命名軸線 (YuleFox 注: 將命名分割在不同類(lèi)的作用域內(nèi)), 命名空間在這基礎(chǔ)上又封裝了一層.

舉例來(lái)說(shuō), 兩個(gè)不同項(xiàng)目的全局作用域都有一個(gè)類(lèi)Foo, 這樣在編譯或運(yùn)行時(shí)造成沖突. 如果每個(gè)項(xiàng)目將代碼置于不同命名空間中,project1::Foo和project2::Foo作為不同符號(hào)自然不會(huì)沖突.

內(nèi)聯(lián)命名空間會(huì)自動(dòng)把內(nèi)部的標(biāo)識(shí)符放到外層作用域,比如:

namespace X {inline namespace Y {void foo();} // namespace Y} // namespace X

X::Y::foo()與X::foo()彼此可代替。內(nèi)聯(lián)命名空間主要用來(lái)保持跨版本的 ABI 兼容性。

缺點(diǎn):

命名空間具有迷惑性, 因?yàn)樗鼈兪沟脜^(qū)分兩個(gè)相同命名所指代的定義更加困難。

內(nèi)聯(lián)命名空間很容易令人迷惑,畢竟其內(nèi)部的成員不再受其聲明所在命名空間的限制。內(nèi)聯(lián)命名空間只在大型版本控制里有用。

有時(shí)候不得不多次引用某個(gè)定義在許多嵌套命名空間里的實(shí)體,使用完整的命名空間會(huì)導(dǎo)致代碼的冗長(zhǎng)。

在頭文件中使用匿名空間導(dǎo)致違背 C++ 的唯一定義原則 (One Definition Rule (ODR)).

結(jié)論:

根據(jù)下文將要提到的策略合理使用命名空間.

遵守命名空間命名中的規(guī)則。

像之前的幾個(gè)例子中一樣,在命名空間的最后注釋出命名空間的名字。

用命名空間把文件包含,gflags的聲明/定義, 以及類(lèi)的前置聲明以外的整個(gè)源文件封裝起來(lái), 以區(qū)別于其它命名空間:

// .h 文件namespace mynamespace {// 所有聲明都置于命名空間中// 注意不要使用縮進(jìn)class MyClass { public: ... void Foo();};} // namespace mynamespace// .cc 文件namespace mynamespace {// 函數(shù)定義都置于命名空間中void MyClass::Foo() { ...}} // namespace mynamespace

更復(fù)雜的.cc文件包含更多, 更復(fù)雜的細(xì)節(jié), 比如 gflags 或 using 聲明。

#include "a.h"DEFINE_FLAG(bool, someflag, false, "dummy flag");namespace a {...code for a... // 左對(duì)齊} // namespace a

不要在命名空間std內(nèi)聲明任何東西, 包括標(biāo)準(zhǔn)庫(kù)的類(lèi)前置聲明. 在std命名空間聲明實(shí)體是未定義的行為, 會(huì)導(dǎo)致如不可移植. 聲明標(biāo)準(zhǔn)庫(kù)下的實(shí)體, 需要包含對(duì)應(yīng)的頭文件.

不應(yīng)該使用using 指示引入整個(gè)命名空間的標(biāo)識(shí)符號(hào)。

// 禁止 —— 污染命名空間using namespace foo;

不要在頭文件中使用命名空間別名除非顯式標(biāo)記內(nèi)部命名空間使用。因?yàn)槿魏卧陬^文件中引入的命名空間都會(huì)成為公開(kāi)API的一部分。

// 在 .cc 中使用別名縮短常用的命名空間namespace baz = ::foo::bar::baz;// 在 .h 中使用別名縮短常用的命名空間namespace librarian {namespace impl { // 僅限內(nèi)部使用namespace sidetable = ::pipeline_diagnostics::sidetable;} // namespace implinline void my_inline_function() { // 限制在一個(gè)函數(shù)中的命名空間別名 namespace baz = ::foo::bar::baz; ...}} // namespace librarian

禁止用內(nèi)聯(lián)命名空間

2.2. 匿名命名空間和靜態(tài)變量

Tip

在.cc文件中定義一個(gè)不需要被外部引用的變量時(shí),可以將它們放在匿名命名空間或聲明為static。但是不要在.h文件中這么做。

定義:

所有置于匿名命名空間的聲明都具有內(nèi)部鏈接性,函數(shù)和變量可以經(jīng)由聲明為static擁有內(nèi)部鏈接性,這意味著你在這個(gè)文件中聲明的這些標(biāo)識(shí)符都不能在另一個(gè)文件中被訪問(wèn)。即使兩個(gè)文件聲明了完全一樣名字的標(biāo)識(shí)符,它們所指向的實(shí)體實(shí)際上是完全不同的。

結(jié)論:

推薦、鼓勵(lì)在.cc中對(duì)于不需要在其他地方引用的標(biāo)識(shí)符使用內(nèi)部鏈接性聲明,但是不要在.h中使用。

匿名命名空間的聲明和具名的格式相同,在最后注釋上namespace:

namespace {...} // namespace

2.3. 非成員函數(shù)、靜態(tài)成員函數(shù)和全局函數(shù)

Tip

使用靜態(tài)成員函數(shù)或命名空間內(nèi)的非成員函數(shù), 盡量不要用裸的全局函數(shù). 將一系列函數(shù)直接置于命名空間中,不要用類(lèi)的靜態(tài)方法模擬出命名空間的效果,類(lèi)的靜態(tài)方法應(yīng)當(dāng)和類(lèi)的實(shí)例或靜態(tài)數(shù)據(jù)緊密相關(guān).

優(yōu)點(diǎn):

某些情況下, 非成員函數(shù)和靜態(tài)成員函數(shù)是非常有用的, 將非成員函數(shù)放在命名空間內(nèi)可避免污染全局作用域.

缺點(diǎn):

將非成員函數(shù)和靜態(tài)成員函數(shù)作為新類(lèi)的成員或許更有意義, 當(dāng)它們需要訪問(wèn)外部資源或具有重要的依賴(lài)關(guān)系時(shí)更是如此.

結(jié)論:

有時(shí), 把函數(shù)的定義同類(lèi)的實(shí)例脫鉤是有益的, 甚至是必要的. 這樣的函數(shù)可以被定義成靜態(tài)成員, 或是非成員函數(shù). 非成員函數(shù)不應(yīng)依賴(lài)于外部變量, 應(yīng)盡量置于某個(gè)命名空間內(nèi). 相比單純?yōu)榱朔庋b若干不共享任何靜態(tài)數(shù)據(jù)的靜態(tài)成員函數(shù)而創(chuàng)建類(lèi), 不如使用2.1. 命名空間。舉例而言,對(duì)于頭文件myproject/foo_bar.h, 應(yīng)當(dāng)使用

namespace myproject {namespace foo_bar {void Function1();void Function2();} // namespace foo_bar} // namespace myproject

而非

namespace myproject {class FooBar { public: static void Function1(); static void Function2();};} // namespace myproject

定義在同一編譯單元的函數(shù), 被其他編譯單元直接調(diào)用可能會(huì)引入不必要的耦合和鏈接時(shí)依賴(lài); 靜態(tài)成員函數(shù)對(duì)此尤其敏感. 可以考慮提取到新類(lèi)中, 或者將函數(shù)置于獨(dú)立庫(kù)的命名空間內(nèi).

如果你必須定義非成員函數(shù), 又只是在.cc文件中使用它, 可使用匿名2.1. 命名空間或static鏈接關(guān)鍵字 (如staticintFoo(){...}) 限定其作用域.

2.4. 局部變量

Tip

將函數(shù)變量盡可能置于最小作用域內(nèi), 并在變量聲明時(shí)進(jìn)行初始化.

C++ 允許在函數(shù)的任何位置聲明變量. 我們提倡在盡可能小的作用域中聲明變量, 離第一次使用越近越好. 這使得代碼瀏覽者更容易定位變量聲明的位置, 了解變量的類(lèi)型和初始值. 特別是,應(yīng)使用初始化的方式替代聲明再賦值, 比如:

int i;i = f(); // 壞——初始化和聲明分離int j = g(); // 好——初始化時(shí)聲明vector v;v.push_back(1); // 用花括號(hào)初始化更好v.push_back(2);vector v = {1, 2}; // 好——v 一開(kāi)始就初始化

屬于if,while和for語(yǔ)句的變量應(yīng)當(dāng)在這些語(yǔ)句中正常地聲明,這樣子這些變量的作用域就被限制在這些語(yǔ)句中了,舉例而言:

while (const char* p = strchr(str, '/')) str = p + 1;

Warning

有一個(gè)例外, 如果變量是一個(gè)對(duì)象, 每次進(jìn)入作用域都要調(diào)用其構(gòu)造函數(shù), 每次退出作用域都要調(diào)用其析構(gòu)函數(shù). 這會(huì)導(dǎo)致效率降低.

// 低效的實(shí)現(xiàn)for (int i = 0; i < 1000000; ++i) { Foo f; // 構(gòu)造函數(shù)和析構(gòu)函數(shù)分別調(diào)用 1000000 次! f.DoSomething(i);}

在循環(huán)作用域外面聲明這類(lèi)變量要高效的多:

Foo f; // 構(gòu)造函數(shù)和析構(gòu)函數(shù)只調(diào)用 1 次for (int i = 0; i < 1000000; ++i) { f.DoSomething(i);}

2.5. 靜態(tài)和全局變量

Tip

禁止定義靜態(tài)儲(chǔ)存周期非POD變量,禁止使用含有副作用的函數(shù)初始化POD全局變量,因?yàn)槎嗑幾g單元中的靜態(tài)變量執(zhí)行時(shí)的構(gòu)造和析構(gòu)順序是未明確的,這將導(dǎo)致代碼的不可移植。

禁止使用類(lèi)的靜態(tài)儲(chǔ)存周期變量:由于構(gòu)造和析構(gòu)函數(shù)調(diào)用順序的不確定性,它們會(huì)導(dǎo)致難以發(fā)現(xiàn)的 bug 。不過(guò)constexpr變量除外,畢竟它們又不涉及動(dòng)態(tài)初始化或析構(gòu)。

靜態(tài)生存周期的對(duì)象,即包括了全局變量,靜態(tài)變量,靜態(tài)類(lèi)成員變量和函數(shù)靜態(tài)變量,都必須是原生數(shù)據(jù)類(lèi)型 (POD : Plain Old Data): 即 int, char 和 float, 以及 POD 類(lèi)型的指針、數(shù)組和結(jié)構(gòu)體。

靜態(tài)變量的構(gòu)造函數(shù)、析構(gòu)函數(shù)和初始化的順序在 C++ 中是只有部分明確的,甚至隨著構(gòu)建變化而變化,導(dǎo)致難以發(fā)現(xiàn)的 bug. 所以除了禁用類(lèi)類(lèi)型的全局變量,我們也不允許用函數(shù)返回值來(lái)初始化 POD 變量,除非該函數(shù)(比如getenv()或getpid())不涉及任何全局變量。函數(shù)作用域里的靜態(tài)變量除外,畢竟它的初始化順序是有明確定義的,而且只會(huì)在指令執(zhí)行到它的聲明那里才會(huì)發(fā)生。

Note

Xris 譯注:

同一個(gè)編譯單元內(nèi)是明確的,靜態(tài)初始化優(yōu)先于動(dòng)態(tài)初始化,初始化順序按照聲明順序進(jìn)行,銷(xiāo)毀則逆序。不同的編譯單元之間初始化和銷(xiāo)毀順序?qū)儆谖疵鞔_行為 (unspecified behaviour)。

同理,全局和靜態(tài)變量在程序中斷時(shí)會(huì)被析構(gòu),無(wú)論所謂中斷是從main()返回還是對(duì)exit()的調(diào)用。析構(gòu)順序正好與構(gòu)造函數(shù)調(diào)用的順序相反。但既然構(gòu)造順序未定義,那么析構(gòu)順序當(dāng)然也就不定了。比如,在程序結(jié)束時(shí)某靜態(tài)變量已經(jīng)被析構(gòu)了,但代碼還在跑——比如其它線程——并試圖訪問(wèn)它且失敗;再比如,一個(gè)靜態(tài) string 變量也許會(huì)在一個(gè)引用了前者的其它變量析構(gòu)之前被析構(gòu)掉。

改善以上析構(gòu)問(wèn)題的辦法之一是用quick_exit()來(lái)代替exit()并中斷程序。它們的不同之處是前者不會(huì)執(zhí)行任何析構(gòu),也不會(huì)執(zhí)行atexit()所綁定的任何 handlers. 如果您想在執(zhí)行quick_exit()來(lái)中斷時(shí)執(zhí)行某 handler(比如刷新 log),您可以把它綁定到_at_quick_exit(). 如果您想在exit()和quick_exit()都用上該 handler, 都綁定上去。

綜上所述,我們只允許 POD 類(lèi)型的靜態(tài)變量,即完全禁用vector(使用 C 數(shù)組替代) 和string(使用constchar[])。

如果您確實(shí)需要一個(gè)class類(lèi)型的靜態(tài)或全局變量,可以考慮在main()函數(shù)或pthread_once()內(nèi)初始化一個(gè)指針且永不回收。注意只能用 raw 指針,別用智能指針,畢竟后者的析構(gòu)函數(shù)涉及到上文指出的不定順序問(wèn)題。

Note

Yang.Y 譯注:

上文提及的靜態(tài)變量泛指靜態(tài)生存周期的對(duì)象, 包括: 全局變量, 靜態(tài)變量, 靜態(tài)類(lèi)成員變量, 以及函數(shù)靜態(tài)變量.

譯者 (YuleFox) 筆記

cc中的匿名命名空間可避免命名沖突, 限定作用域, 避免直接使用using關(guān)鍵字污染命名空間;

嵌套類(lèi)符合局部使用原則, 只是不能在其他頭文件中前置聲明, 盡量不要public;

盡量不用全局函數(shù)和全局變量, 考慮作用域和命名空間限制, 盡量單獨(dú)形成編譯單元;

多線程中的全局變量 (含靜態(tài)成員變量) 不要使用class類(lèi)型 (含 STL 容器), 避免不明確行為導(dǎo)致的 bug.

作用域的使用, 除了考慮名稱(chēng)污染, 可讀性之外, 主要是為降低耦合, 提高編譯/執(zhí)行效率.

譯者(acgtyrant)筆記

注意「using 指示(using-directive)」和「using 聲明(using-declaration)」的區(qū)別。

匿名命名空間說(shuō)白了就是文件作用域,就像 C static 聲明的作用域一樣,后者已經(jīng)被 C++ 標(biāo)準(zhǔn)提倡棄用。

局部變量在聲明的同時(shí)進(jìn)行顯式值初始化,比起隱式初始化再賦值的兩步過(guò)程要高效,同時(shí)也貫徹了計(jì)算機(jī)體系結(jié)構(gòu)重要的概念「局部性(locality)」。

注意別在循環(huán)犯大量構(gòu)造和析構(gòu)的低級(jí)錯(cuò)誤。

3. 類(lèi)

類(lèi)是 C++ 中代碼的基本單元. 顯然, 它們被廣泛使用. 本節(jié)列舉了在寫(xiě)一個(gè)類(lèi)時(shí)的主要注意事項(xiàng).

3.1. 構(gòu)造函數(shù)的職責(zé)

總述

不要在構(gòu)造函數(shù)中調(diào)用虛函數(shù), 也不要在無(wú)法報(bào)出錯(cuò)誤時(shí)進(jìn)行可能失敗的初始化.

定義

在構(gòu)造函數(shù)中可以進(jìn)行各種初始化操作.

優(yōu)點(diǎn)

無(wú)需考慮類(lèi)是否被初始化.

經(jīng)過(guò)構(gòu)造函數(shù)完全初始化后的對(duì)象可以為const類(lèi)型, 也能更方便地被標(biāo)準(zhǔn)容器或算法使用.

缺點(diǎn)

如果在構(gòu)造函數(shù)內(nèi)調(diào)用了自身的虛函數(shù), 這類(lèi)調(diào)用是不會(huì)重定向到子類(lèi)的虛函數(shù)實(shí)現(xiàn). 即使當(dāng)前沒(méi)有子類(lèi)化實(shí)現(xiàn), 將來(lái)仍是隱患.

在沒(méi)有使程序崩潰 (因?yàn)椴⒉皇且粋€(gè)始終合適的方法) 或者使用異常 (因?yàn)橐呀?jīng)被禁用了) 等方法的條件下, 構(gòu)造函數(shù)很難上報(bào)錯(cuò)誤

如果執(zhí)行失敗, 會(huì)得到一個(gè)初始化失敗的對(duì)象, 這個(gè)對(duì)象有可能進(jìn)入不正常的狀態(tài), 必須使用boolisValid()或類(lèi)似這樣的機(jī)制才能檢查出來(lái), 然而這是一個(gè)十分容易被疏忽的方法.

構(gòu)造函數(shù)的地址是無(wú)法被取得的, 因此, 舉例來(lái)說(shuō), 由構(gòu)造函數(shù)完成的工作是無(wú)法以簡(jiǎn)單的方式交給其他線程的.

結(jié)論

構(gòu)造函數(shù)不允許調(diào)用虛函數(shù). 如果代碼允許, 直接終止程序是一個(gè)合適的處理錯(cuò)誤的方式. 否則, 考慮用Init()方法或工廠函數(shù).

構(gòu)造函數(shù)不得調(diào)用虛函數(shù), 或嘗試報(bào)告一個(gè)非致命錯(cuò)誤. 如果對(duì)象需要進(jìn)行有意義的 (non-trivial) 初始化, 考慮使用明確的 Init() 方法或使用工廠模式. AvoidInit()methods on objects with no other states that affect which public methods may be called (此類(lèi)形式的半構(gòu)造對(duì)象有時(shí)無(wú)法正確工作).

3.2. 隱式類(lèi)型轉(zhuǎn)換

總述

不要定義隱式類(lèi)型轉(zhuǎn)換. 對(duì)于轉(zhuǎn)換運(yùn)算符和單參數(shù)構(gòu)造函數(shù), 請(qǐng)使用explicit關(guān)鍵字.

定義

隱式類(lèi)型轉(zhuǎn)換允許一個(gè)某種類(lèi)型 (稱(chēng)作源類(lèi)型) 的對(duì)象被用于需要另一種類(lèi)型 (稱(chēng)作目的類(lèi)型) 的位置, 例如, 將一個(gè)int類(lèi)型的參數(shù)傳遞給需要double類(lèi)型的函數(shù).

除了語(yǔ)言所定義的隱式類(lèi)型轉(zhuǎn)換, 用戶(hù)還可以通過(guò)在類(lèi)定義中添加合適的成員定義自己需要的轉(zhuǎn)換. 在源類(lèi)型中定義隱式類(lèi)型轉(zhuǎn)換, 可以通過(guò)目的類(lèi)型名的類(lèi)型轉(zhuǎn)換運(yùn)算符實(shí)現(xiàn) (例如operatorbool()). 在目的類(lèi)型中定義隱式類(lèi)型轉(zhuǎn)換, 則通過(guò)以源類(lèi)型作為其唯一參數(shù) (或唯一無(wú)默認(rèn)值的參數(shù)) 的構(gòu)造函數(shù)實(shí)現(xiàn).

explicit關(guān)鍵字可以用于構(gòu)造函數(shù)或 (在 C++11 引入) 類(lèi)型轉(zhuǎn)換運(yùn)算符, 以保證只有當(dāng)目的類(lèi)型在調(diào)用點(diǎn)被顯式寫(xiě)明時(shí)才能進(jìn)行類(lèi)型轉(zhuǎn)換, 例如使用cast. 這不僅作用于隱式類(lèi)型轉(zhuǎn)換, 還能作用于 C++11 的列表初始化語(yǔ)法:

class Foo { explicit Foo(int x, double y); ...};void Func(Foo f);

此時(shí)下面的代碼是不允許的:

Func({42, 3.14}); // Error

這一代碼從技術(shù)上說(shuō)并非隱式類(lèi)型轉(zhuǎn)換, 但是語(yǔ)言標(biāo)準(zhǔn)認(rèn)為這是explicit應(yīng)當(dāng)限制的行為.

優(yōu)點(diǎn)

有時(shí)目的類(lèi)型名是一目了然的, 通過(guò)避免顯式地寫(xiě)出類(lèi)型名, 隱式類(lèi)型轉(zhuǎn)換可以讓一個(gè)類(lèi)型的可用性和表達(dá)性更強(qiáng).

隱式類(lèi)型轉(zhuǎn)換可以簡(jiǎn)單地取代函數(shù)重載.

在初始化對(duì)象時(shí), 列表初始化語(yǔ)法是一種簡(jiǎn)潔明了的寫(xiě)法.

缺點(diǎn)

隱式類(lèi)型轉(zhuǎn)換會(huì)隱藏類(lèi)型不匹配的錯(cuò)誤. 有時(shí), 目的類(lèi)型并不符合用戶(hù)的期望, 甚至用戶(hù)根本沒(méi)有意識(shí)到發(fā)生了類(lèi)型轉(zhuǎn)換.

隱式類(lèi)型轉(zhuǎn)換會(huì)讓代碼難以閱讀, 尤其是在有函數(shù)重載的時(shí)候, 因?yàn)檫@時(shí)很難判斷到底是哪個(gè)函數(shù)被調(diào)用.

單參數(shù)構(gòu)造函數(shù)有可能會(huì)被無(wú)意地用作隱式類(lèi)型轉(zhuǎn)換.

如果單參數(shù)構(gòu)造函數(shù)沒(méi)有加上explicit關(guān)鍵字, 讀者無(wú)法判斷這一函數(shù)究竟是要作為隱式類(lèi)型轉(zhuǎn)換, 還是作者忘了加上explicit標(biāo)記.

并沒(méi)有明確的方法用來(lái)判斷哪個(gè)類(lèi)應(yīng)該提供類(lèi)型轉(zhuǎn)換, 這會(huì)使得代碼變得含糊不清.

如果目的類(lèi)型是隱式指定的, 那么列表初始化會(huì)出現(xiàn)和隱式類(lèi)型轉(zhuǎn)換一樣的問(wèn)題, 尤其是在列表中只有一個(gè)元素的時(shí)候.

結(jié)論

在類(lèi)型定義中, 類(lèi)型轉(zhuǎn)換運(yùn)算符和單參數(shù)構(gòu)造函數(shù)都應(yīng)當(dāng)用explicit進(jìn)行標(biāo)記. 一個(gè)例外是, 拷貝和移動(dòng)構(gòu)造函數(shù)不應(yīng)當(dāng)被標(biāo)記為explicit, 因?yàn)樗鼈儾⒉粓?zhí)行類(lèi)型轉(zhuǎn)換. 對(duì)于設(shè)計(jì)目的就是用于對(duì)其他類(lèi)型進(jìn)行透明包裝的類(lèi)來(lái)說(shuō), 隱式類(lèi)型轉(zhuǎn)換有時(shí)是必要且合適的. 這時(shí)應(yīng)當(dāng)聯(lián)系項(xiàng)目組長(zhǎng)并說(shuō)明特殊情況.

不能以一個(gè)參數(shù)進(jìn)行調(diào)用的構(gòu)造函數(shù)不應(yīng)當(dāng)加上explicit. 接受一個(gè)std::initializer_list作為參數(shù)的構(gòu)造函數(shù)也應(yīng)當(dāng)省略explicit, 以便支持拷貝初始化 (例如MyTypem={1,2};).

3.3. 可拷貝類(lèi)型和可移動(dòng)類(lèi)型

總述

如果你的類(lèi)型需要, 就讓它們支持拷貝 / 移動(dòng). 否則, 就把隱式產(chǎn)生的拷貝和移動(dòng)函數(shù)禁用.

定義

可拷貝類(lèi)型允許對(duì)象在初始化時(shí)得到來(lái)自相同類(lèi)型的另一對(duì)象的值, 或在賦值時(shí)被賦予相同類(lèi)型的另一對(duì)象的值, 同時(shí)不改變?cè)磳?duì)象的值. 對(duì)于用戶(hù)定義的類(lèi)型, 拷貝操作一般通過(guò)拷貝構(gòu)造函數(shù)與拷貝賦值操作符定義.string類(lèi)型就是一個(gè)可拷貝類(lèi)型的例子.

可移動(dòng)類(lèi)型允許對(duì)象在初始化時(shí)得到來(lái)自相同類(lèi)型的臨時(shí)對(duì)象的值, 或在賦值時(shí)被賦予相同類(lèi)型的臨時(shí)對(duì)象的值 (因此所有可拷貝對(duì)象也是可移動(dòng)的).std::unique_ptr就是一個(gè)可移動(dòng)但不可復(fù)制的對(duì)象的例子. 對(duì)于用戶(hù)定義的類(lèi)型, 移動(dòng)操作一般是通過(guò)移動(dòng)構(gòu)造函數(shù)和移動(dòng)賦值操作符實(shí)現(xiàn)的.

拷貝 / 移動(dòng)構(gòu)造函數(shù)在某些情況下會(huì)被編譯器隱式調(diào)用. 例如, 通過(guò)傳值的方式傳遞對(duì)象.

優(yōu)點(diǎn)

可移動(dòng)及可拷貝類(lèi)型的對(duì)象可以通過(guò)傳值的方式進(jìn)行傳遞或者返回, 這使得 API 更簡(jiǎn)單, 更安全也更通用. 與傳指針和引用不同, 這樣的傳遞不會(huì)造成所有權(quán), 生命周期, 可變性等方面的混亂, 也就沒(méi)必要在協(xié)議中予以明確. 這同時(shí)也防止了客戶(hù)端與實(shí)現(xiàn)在非作用域內(nèi)的交互, 使得它們更容易被理解與維護(hù). 這樣的對(duì)象可以和需要傳值操作的通用 API 一起使用, 例如大多數(shù)容器.

拷貝 / 移動(dòng)構(gòu)造函數(shù)與賦值操作一般來(lái)說(shuō)要比它們的各種替代方案, 比如Clone(),CopyFrom()orSwap(), 更容易定義, 因?yàn)樗鼈兡芡ㄟ^(guò)編譯器產(chǎn)生, 無(wú)論是隱式的還是通過(guò)=default. 這種方式很簡(jiǎn)潔, 也保證所有數(shù)據(jù)成員都會(huì)被復(fù)制. 拷貝與移動(dòng)構(gòu)造函數(shù)一般也更高效, 因?yàn)樗鼈儾恍枰训姆峙浠蛘呤菃为?dú)的初始化和賦值步驟, 同時(shí), 對(duì)于類(lèi)似省略不必要的拷貝這樣的優(yōu)化它們也更加合適.

移動(dòng)操作允許隱式且高效地將源數(shù)據(jù)轉(zhuǎn)移出右值對(duì)象. 這有時(shí)能讓代碼風(fēng)格更加清晰.

缺點(diǎn)

許多類(lèi)型都不需要拷貝, 為它們提供拷貝操作會(huì)讓人迷惑, 也顯得荒謬而不合理. 單件類(lèi)型 (Registerer), 與特定的作用域相關(guān)的類(lèi)型 (Cleanup), 與其他對(duì)象實(shí)體緊耦合的類(lèi)型 (Mutex) 從邏輯上來(lái)說(shuō)都不應(yīng)該提供拷貝操作. 為基類(lèi)提供拷貝 / 賦值操作是有害的, 因?yàn)樵谑褂盟鼈儠r(shí)會(huì)造成對(duì)象切割. 默認(rèn)的或者隨意的拷貝操作實(shí)現(xiàn)可能是不正確的, 這往往導(dǎo)致令人困惑并且難以診斷出的錯(cuò)誤.

拷貝構(gòu)造函數(shù)是隱式調(diào)用的, 也就是說(shuō), 這些調(diào)用很容易被忽略. 這會(huì)讓人迷惑, 尤其是對(duì)那些所用的語(yǔ)言約定或強(qiáng)制要求傳引用的程序員來(lái)說(shuō)更是如此. 同時(shí), 這從一定程度上說(shuō)會(huì)鼓勵(lì)過(guò)度拷貝, 從而導(dǎo)致性能上的問(wèn)題.

結(jié)論

如果需要就讓你的類(lèi)型可拷貝 / 可移動(dòng). 作為一個(gè)經(jīng)驗(yàn)法則, 如果對(duì)于你的用戶(hù)來(lái)說(shuō)這個(gè)拷貝操作不是一眼就能看出來(lái)的, 那就不要把類(lèi)型設(shè)置為可拷貝. 如果讓類(lèi)型可拷貝, 一定要同時(shí)給出拷貝構(gòu)造函數(shù)和賦值操作的定義, 反之亦然. 如果讓類(lèi)型可拷貝, 同時(shí)移動(dòng)操作的效率高于拷貝操作, 那么就把移動(dòng)的兩個(gè)操作 (移動(dòng)構(gòu)造函數(shù)和賦值操作) 也給出定義. 如果類(lèi)型不可拷貝, 但是移動(dòng)操作的正確性對(duì)用戶(hù)顯然可見(jiàn), 那么把這個(gè)類(lèi)型設(shè)置為只可移動(dòng)并定義移動(dòng)的兩個(gè)操作.

如果定義了拷貝/移動(dòng)操作, 則要保證這些操作的默認(rèn)實(shí)現(xiàn)是正確的. 記得時(shí)刻檢查默認(rèn)操作的正確性, 并且在文檔中說(shuō)明類(lèi)是可拷貝的且/或可移動(dòng)的.

class Foo { public: Foo(Foo&& other) : field_(other.field) {} // 差, 只定義了移動(dòng)構(gòu)造函數(shù), 而沒(méi)有定義對(duì)應(yīng)的賦值運(yùn)算符. private: Field field_;};

由于存在對(duì)象切割的風(fēng)險(xiǎn), 不要為任何有可能有派生類(lèi)的對(duì)象提供賦值操作或者拷貝 / 移動(dòng)構(gòu)造函數(shù) (當(dāng)然也不要繼承有這樣的成員函數(shù)的類(lèi)). 如果你的基類(lèi)需要可復(fù)制屬性, 請(qǐng)?zhí)峁┮粋€(gè)publicvirtualClone()和一個(gè)protected的拷貝構(gòu)造函數(shù)以供派生類(lèi)實(shí)現(xiàn).

如果你的類(lèi)不需要拷貝 / 移動(dòng)操作, 請(qǐng)顯式地通過(guò)在public域中使用=delete或其他手段禁用之.

// MyClass is neither copyable nor movable.MyClass(const MyClass&) = delete;MyClass& operator=(const MyClass&) = delete;

3.4. 結(jié)構(gòu)體 VS. 類(lèi)

總述

僅當(dāng)只有數(shù)據(jù)成員時(shí)使用struct, 其它一概使用class.

說(shuō)明

在 C++ 中struct和class關(guān)鍵字幾乎含義一樣. 我們?yōu)檫@兩個(gè)關(guān)鍵字添加我們自己的語(yǔ)義理解, 以便為定義的數(shù)據(jù)類(lèi)型選擇合適的關(guān)鍵字.

struct用來(lái)定義包含數(shù)據(jù)的被動(dòng)式對(duì)象, 也可以包含相關(guān)的常量, 但除了存取數(shù)據(jù)成員之外, 沒(méi)有別的函數(shù)功能. 并且存取功能是通過(guò)直接訪問(wèn)位域, 而非函數(shù)調(diào)用. 除了構(gòu)造函數(shù), 析構(gòu)函數(shù),Initialize(),Reset(),Validate()等類(lèi)似的用于設(shè)定數(shù)據(jù)成員的函數(shù)外, 不能提供其它功能的函數(shù).

如果需要更多的函數(shù)功能,class更適合. 如果拿不準(zhǔn), 就用class.

為了和 STL 保持一致, 對(duì)于仿函數(shù)等特性可以不用class而是使用struct.

注意: 類(lèi)和結(jié)構(gòu)體的成員變量使用不同的命名規(guī)則.

3.5. 繼承

總述

使用組合 (YuleFox 注: 這一點(diǎn)也是 GoF 在 <> 里反復(fù)強(qiáng)調(diào)的) 常常比使用繼承更合理. 如果使用繼承的話, 定義為public繼承.

定義

當(dāng)子類(lèi)繼承基類(lèi)時(shí), 子類(lèi)包含了父基類(lèi)所有數(shù)據(jù)及操作的定義. C++ 實(shí)踐中, 繼承主要用于兩種場(chǎng)合: 實(shí)現(xiàn)繼承, 子類(lèi)繼承父類(lèi)的實(shí)現(xiàn)代碼;接口繼承, 子類(lèi)僅繼承父類(lèi)的方法名稱(chēng).

優(yōu)點(diǎn)

實(shí)現(xiàn)繼承通過(guò)原封不動(dòng)的復(fù)用基類(lèi)代碼減少了代碼量. 由于繼承是在編譯時(shí)聲明, 程序員和編譯器都可以理解相應(yīng)操作并發(fā)現(xiàn)錯(cuò)誤. 從編程角度而言, 接口繼承是用來(lái)強(qiáng)制類(lèi)輸出特定的 API. 在類(lèi)沒(méi)有實(shí)現(xiàn) API 中某個(gè)必須的方法時(shí), 編譯器同樣會(huì)發(fā)現(xiàn)并報(bào)告錯(cuò)誤.

缺點(diǎn)

對(duì)于實(shí)現(xiàn)繼承, 由于子類(lèi)的實(shí)現(xiàn)代碼散布在父類(lèi)和子類(lèi)間之間, 要理解其實(shí)現(xiàn)變得更加困難. 子類(lèi)不能重寫(xiě)父類(lèi)的非虛函數(shù), 當(dāng)然也就不能修改其實(shí)現(xiàn). 基類(lèi)也可能定義了一些數(shù)據(jù)成員, 因此還必須區(qū)分基類(lèi)的實(shí)際布局.

結(jié)論

所有繼承必須是public的. 如果你想使用私有繼承, 你應(yīng)該替換成把基類(lèi)的實(shí)例作為成員對(duì)象的方式.

不要過(guò)度使用實(shí)現(xiàn)繼承. 組合常常更合適一些. 盡量做到只在 “是一個(gè)” (“is-a”, YuleFox 注: 其他 “has-a” 情況下請(qǐng)使用組合) 的情況下使用繼承: 如果Bar的確 “是一種”Foo,Bar才能繼承Foo.

必要的話, 析構(gòu)函數(shù)聲明為virtual. 如果你的類(lèi)有虛函數(shù), 則析構(gòu)函數(shù)也應(yīng)該為虛函數(shù).

對(duì)于可能被子類(lèi)訪問(wèn)的成員函數(shù), 不要過(guò)度使用protected關(guān)鍵字. 注意, 數(shù)據(jù)成員都必須是私有的.

對(duì)于重載的虛函數(shù)或虛析構(gòu)函數(shù), 使用override, 或 (較不常用的)final關(guān)鍵字顯式地進(jìn)行標(biāo)記. 較早 (早于 C++11) 的代碼可能會(huì)使用virtual關(guān)鍵字作為不得已的選項(xiàng). 因此, 在聲明重載時(shí), 請(qǐng)使用override,final或virtual的其中之一進(jìn)行標(biāo)記. 標(biāo)記為override或final的析構(gòu)函數(shù)如果不是對(duì)基類(lèi)虛函數(shù)的重載的話, 編譯會(huì)報(bào)錯(cuò), 這有助于捕獲常見(jiàn)的錯(cuò)誤. 這些標(biāo)記起到了文檔的作用, 因?yàn)槿绻÷赃@些關(guān)鍵字, 代碼閱讀者不得不檢查所有父類(lèi), 以判斷該函數(shù)是否是虛函數(shù).

3.6. 多重繼承

總述

真正需要用到多重實(shí)現(xiàn)繼承的情況少之又少. 只在以下情況我們才允許多重繼承: 最多只有一個(gè)基類(lèi)是非抽象類(lèi); 其它基類(lèi)都是以Interface為后綴的純接口類(lèi).

定義

多重繼承允許子類(lèi)擁有多個(gè)基類(lèi). 要將作為純接口的基類(lèi)和具有實(shí)現(xiàn)的基類(lèi)區(qū)別開(kāi)來(lái).

優(yōu)點(diǎn)

相比單繼承 (見(jiàn)繼承), 多重實(shí)現(xiàn)繼承可以復(fù)用更多的代碼.

缺點(diǎn)

真正需要用到多重實(shí)現(xiàn)繼承的情況少之又少. 有時(shí)多重實(shí)現(xiàn)繼承看上去是不錯(cuò)的解決方案, 但這時(shí)你通常也可以找到一個(gè)更明確, 更清晰的不同解決方案.

結(jié)論

只有當(dāng)所有父類(lèi)除第一個(gè)外都是純接口類(lèi)時(shí), 才允許使用多重繼承. 為確保它們是純接口, 這些類(lèi)必須以Interface為后綴.

注意

關(guān)于該規(guī)則, Windows 下有個(gè)特例.

3.7. 接口

總述

接口是指滿(mǎn)足特定條件的類(lèi), 這些類(lèi)以Interface為后綴 (不強(qiáng)制).

定義

當(dāng)一個(gè)類(lèi)滿(mǎn)足以下要求時(shí), 稱(chēng)之為純接口:

只有純虛函數(shù) (“=0”) 和靜態(tài)函數(shù) (除了下文提到的析構(gòu)函數(shù)).

沒(méi)有非靜態(tài)數(shù)據(jù)成員.

沒(méi)有定義任何構(gòu)造函數(shù). 如果有, 也不能帶有參數(shù), 并且必須為protected.

如果它是一個(gè)子類(lèi), 也只能從滿(mǎn)足上述條件并以Interface為后綴的類(lèi)繼承.

接口類(lèi)不能被直接實(shí)例化, 因?yàn)樗暶髁思兲摵瘮?shù). 為確保接口類(lèi)的所有實(shí)現(xiàn)可被正確銷(xiāo)毀, 必須為之聲明虛析構(gòu)函數(shù) (作為上述第 1 條規(guī)則的特例, 析構(gòu)函數(shù)不能是純虛函數(shù)). 具體細(xì)節(jié)可參考 Stroustrup 的The C++ Programming Language, 3rd edition第 12.4 節(jié).

優(yōu)點(diǎn)

以Interface為后綴可以提醒其他人不要為該接口類(lèi)增加函數(shù)實(shí)現(xiàn)或非靜態(tài)數(shù)據(jù)成員. 這一點(diǎn)對(duì)于多重繼承尤其重要. 另外, 對(duì)于 Java 程序員來(lái)說(shuō), 接口的概念已是深入人心.

缺點(diǎn)

Interface后綴增加了類(lèi)名長(zhǎng)度, 為閱讀和理解帶來(lái)不便. 同時(shí), 接口屬性作為實(shí)現(xiàn)細(xì)節(jié)不應(yīng)暴露給用戶(hù).

結(jié)論

只有在滿(mǎn)足上述條件時(shí), 類(lèi)才以Interface結(jié)尾, 但反過(guò)來(lái), 滿(mǎn)足上述需要的類(lèi)未必一定以Interface結(jié)尾.

3.8. 運(yùn)算符重載

總述

除少數(shù)特定環(huán)境外, 不要重載運(yùn)算符. 也不要?jiǎng)?chuàng)建用戶(hù)定義字面量.

定義

C++ 允許用戶(hù)通過(guò)使用operator關(guān)鍵字對(duì)內(nèi)建運(yùn)算符進(jìn)行重載定義, 只要其中一個(gè)參數(shù)是用戶(hù)定義的類(lèi)型.operator關(guān)鍵字還允許用戶(hù)使用operator""定義新的字面運(yùn)算符, 并且定義類(lèi)型轉(zhuǎn)換函數(shù), 例如operatorbool().

優(yōu)點(diǎn)

重載運(yùn)算符可以讓代碼更簡(jiǎn)潔易懂, 也使得用戶(hù)定義的類(lèi)型和內(nèi)建類(lèi)型擁有相似的行為. 重載運(yùn)算符對(duì)于某些運(yùn)算來(lái)說(shuō)是符合符合語(yǔ)言習(xí)慣的名稱(chēng) (例如==,<,?=,?<<), 遵循這些語(yǔ)言約定可以讓用戶(hù)定義的類(lèi)型更易讀, 也能更好地和需要這些重載運(yùn)算符的函數(shù)庫(kù)進(jìn)行交互操作.

對(duì)于創(chuàng)建用戶(hù)定義的類(lèi)型的對(duì)象來(lái)說(shuō), 用戶(hù)定義字面量是一種非常簡(jiǎn)潔的標(biāo)記.

缺點(diǎn)

要提供正確, 一致, 不出現(xiàn)異常行為的操作符運(yùn)算需要花費(fèi)不少精力, 而且如果達(dá)不到這些要求的話, 會(huì)導(dǎo)致令人迷惑的 Bug.

過(guò)度使用運(yùn)算符會(huì)帶來(lái)難以理解的代碼, 尤其是在重載的操作符的語(yǔ)義與通常的約定不符合時(shí).

函數(shù)重載有多少弊端, 運(yùn)算符重載就至少有多少.

運(yùn)算符重載會(huì)混淆視聽(tīng), 讓你誤以為一些耗時(shí)的操作和操作內(nèi)建類(lèi)型一樣輕巧.

對(duì)重載運(yùn)算符的調(diào)用點(diǎn)的查找需要的可就不僅僅是像 grep 那樣的程序了, 這時(shí)需要能夠理解 C++ 語(yǔ)法的搜索工具.

如果重載運(yùn)算符的參數(shù)寫(xiě)錯(cuò), 此時(shí)得到的可能是一個(gè)完全不同的重載而非編譯錯(cuò)誤. 例如:foo

重載某些運(yùn)算符本身就是有害的. 例如, 重載一元運(yùn)算符&會(huì)導(dǎo)致同樣的代碼有完全不同的含義, 這取決于重載的聲明對(duì)某段代碼而言是否是可見(jiàn)的. 重載諸如&&,||和,會(huì)導(dǎo)致運(yùn)算順序和內(nèi)建運(yùn)算的順序不一致.

運(yùn)算符從通常定義在類(lèi)的外部, 所以對(duì)于同一運(yùn)算, 可能出現(xiàn)不同的文件引入了不同的定義的風(fēng)險(xiǎn). 如果兩種定義都鏈接到同一二進(jìn)制文件, 就會(huì)導(dǎo)致未定義的行為, 有可能表現(xiàn)為難以發(fā)現(xiàn)的運(yùn)行時(shí)錯(cuò)誤.

用戶(hù)定義字面量所創(chuàng)建的語(yǔ)義形式對(duì)于某些有經(jīng)驗(yàn)的 C++ 程序員來(lái)說(shuō)都是很陌生的.

結(jié)論

只有在意義明顯, 不會(huì)出現(xiàn)奇怪的行為并且與對(duì)應(yīng)的內(nèi)建運(yùn)算符的行為一致時(shí)才定義重載運(yùn)算符. 例如,|要作為位或或邏輯或來(lái)使用, 而不是作為 shell 中的管道.

只有對(duì)用戶(hù)自己定義的類(lèi)型重載運(yùn)算符. 更準(zhǔn)確地說(shuō), 將它們和它們所操作的類(lèi)型定義在同一個(gè)頭文件中,.cc中和命名空間中. 這樣做無(wú)論類(lèi)型在哪里都能夠使用定義的運(yùn)算符, 并且最大程度上避免了多重定義的風(fēng)險(xiǎn). 如果可能的話, 請(qǐng)避免將運(yùn)算符定義為模板, 因?yàn)榇藭r(shí)它們必須對(duì)任何模板參數(shù)都能夠作用. 如果你定義了一個(gè)運(yùn)算符, 請(qǐng)將其相關(guān)且有意義的運(yùn)算符都進(jìn)行定義, 并且保證這些定義的語(yǔ)義是一致的. 例如, 如果你重載了<, 那么請(qǐng)將所有的比較運(yùn)算符都進(jìn)行重載, 并且保證對(duì)于同一組參數(shù),?不會(huì)同時(shí)返回true.

建議不要將不進(jìn)行修改的二元運(yùn)算符定義為成員函數(shù). 如果一個(gè)二元運(yùn)算符被定義為類(lèi)成員, 這時(shí)隱式轉(zhuǎn)換會(huì)作用域右側(cè)的參數(shù)卻不會(huì)作用于左側(cè). 這時(shí)會(huì)出現(xiàn)a

不要為了避免重載操作符而走極端. 比如說(shuō), 應(yīng)當(dāng)定義==,=, 和<

不要重載&&,||,,或一元運(yùn)算符&. 不要重載operator"", 也就是說(shuō), 不要引入用戶(hù)定義字面量.

類(lèi)型轉(zhuǎn)換運(yùn)算符在隱式類(lèi)型轉(zhuǎn)換一節(jié)有提及.=運(yùn)算符在可拷貝類(lèi)型和可移動(dòng)類(lèi)型一節(jié)有提及. 運(yùn)算符<

3.9. 存取控制

總述

將所有數(shù)據(jù)成員聲明為private, 除非是staticconst類(lèi)型成員 (遵循常量命名規(guī)則). 處于技術(shù)上的原因, 在使用Google Test時(shí)我們?cè)试S測(cè)試固件類(lèi)中的數(shù)據(jù)成員為protected.

3.10. 聲明順序

總述

將相似的聲明放在一起, 將public部分放在最前.

說(shuō)明

類(lèi)定義一般應(yīng)以public:開(kāi)始, 后跟protected:, 最后是private:. 省略空部分.

在各個(gè)部分中, 建議將類(lèi)似的聲明放在一起, 并且建議以如下的順序: 類(lèi)型 (包括typedef,using和嵌套的結(jié)構(gòu)體與類(lèi)), 常量, 工廠函數(shù), 構(gòu)造函數(shù), 賦值運(yùn)算符, 析構(gòu)函數(shù), 其它函數(shù), 數(shù)據(jù)成員.

不要將大段的函數(shù)定義內(nèi)聯(lián)在類(lèi)定義中. 通常,只有那些普通的, 或性能關(guān)鍵且短小的函數(shù)可以?xún)?nèi)聯(lián)在類(lèi)定義中. 參見(jiàn)內(nèi)聯(lián)函數(shù)一節(jié).

譯者 (YuleFox) 筆記

不在構(gòu)造函數(shù)中做太多邏輯相關(guān)的初始化;

編譯器提供的默認(rèn)構(gòu)造函數(shù)不會(huì)對(duì)變量進(jìn)行初始化, 如果定義了其他構(gòu)造函數(shù), 編譯器不再提供, 需要編碼者自行提供默認(rèn)構(gòu)造函數(shù);

為避免隱式轉(zhuǎn)換, 需將單參數(shù)構(gòu)造函數(shù)聲明為explicit;

為避免拷貝構(gòu)造函數(shù), 賦值操作的濫用和編譯器自動(dòng)生成, 可將其聲明為private且無(wú)需實(shí)現(xiàn);

僅在作為數(shù)據(jù)集合時(shí)使用struct;

組合 > 實(shí)現(xiàn)繼承 > 接口繼承 > 私有繼承, 子類(lèi)重載的虛函數(shù)也要聲明virtual關(guān)鍵字, 雖然編譯器允許不這樣做;

避免使用多重繼承, 使用時(shí), 除一個(gè)基類(lèi)含有實(shí)現(xiàn)外, 其他基類(lèi)均為純接口;

接口類(lèi)類(lèi)名以Interface為后綴, 除提供帶實(shí)現(xiàn)的虛析構(gòu)函數(shù), 靜態(tài)成員函數(shù)外, 其他均為純虛函數(shù), 不定義非靜態(tài)數(shù)據(jù)成員, 不提供構(gòu)造函數(shù), 提供的話, 聲明為protected;

為降低復(fù)雜性, 盡量不重載操作符, 模板, 標(biāo)準(zhǔn)類(lèi)中使用時(shí)提供文檔說(shuō)明;

存取函數(shù)一般內(nèi)聯(lián)在頭文件中;

聲明次序:public->protected->private;

函數(shù)體盡量短小, 緊湊, 功能單一;

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • Google
    +關(guān)注

    關(guān)注

    5

    文章

    1782

    瀏覽量

    58494
  • 編程
    +關(guān)注

    關(guān)注

    88

    文章

    3673

    瀏覽量

    94687
  • C++
    C++
    +關(guān)注

    關(guān)注

    22

    文章

    2116

    瀏覽量

    74553

原文標(biāo)題:Google C++ 編程規(guī)范 - 2

文章出處:【微信號(hào):C_Expert,微信公眾號(hào):C語(yǔ)言專(zhuān)家集中營(yíng)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    MATLAB 編程風(fēng)格指南

    thebeginning.”(良好的寫(xiě)作規(guī)范的程序比糟糕的寫(xiě)作規(guī)范的要好,因?yàn)樗麄兙哂休^少的錯(cuò)誤、易于調(diào)試與修改,因此,從一開(kāi)始就考慮風(fēng)格是很重要的)。本指南列舉的MATLAB 代碼編寫(xiě)的建議在
    發(fā)表于 09-22 16:19

    GUN linux編程指南

    分享一本好書(shū)《GUN linux編程指南(第版)》,希望能幫助大家。。
    發(fā)表于 11-24 09:09

    Google C++編程指南

    Google C++編程指南目標(biāo):增強(qiáng)代碼一致性,創(chuàng)建通用的、必需的習(xí)慣用語(yǔ)和模式可以使代碼更加容易理解C++是一門(mén)包含大量高級(jí)特性的巨型語(yǔ)言,某些情況下,我們會(huì)限制甚至禁止使用某些特性使代碼簡(jiǎn)化
    發(fā)表于 11-29 09:15

    MATLAB編程風(fēng)格指南

    有關(guān) MATLAB代碼的建議通常強(qiáng)調(diào)的是效率,譬如說(shuō)有關(guān)“不要用循環(huán)”等的建議,本指南與之不同。本指南主要考慮的是代碼(格式)的正確性、清晰性與通用性。本指南的目的在
    發(fā)表于 07-18 10:54 ?0次下載

    linux內(nèi)核C語(yǔ)言的編程風(fēng)格

    linux 內(nèi)核C語(yǔ)言的編程風(fēng)格
    發(fā)表于 09-26 14:22 ?0次下載

    Google編程風(fēng)格指南(一)

    使代碼易于管理的方法之一是加強(qiáng)代碼一致性. 讓任何程序員都可以快速讀懂你的代碼這點(diǎn)非常重要. 保持統(tǒng)一編程風(fēng)格并遵守約定意味著可以很容易根據(jù) “模式匹配” 規(guī)則來(lái)推斷各種標(biāo)識(shí)符的含義. 創(chuàng)建通用
    的頭像 發(fā)表于 09-27 17:57 ?3237次閱讀

    Google編程風(fēng)格指南(三)

    C/C++ 中的函數(shù)參數(shù)或者是函數(shù)的輸入, 或者是函數(shù)的輸出, 或兼而有之. 輸入?yún)?shù)通常是值參或 const 引用, 輸出參數(shù)或輸入/輸出參數(shù)則一般為非 const 指針. 在排列參數(shù)順序時(shí), 將所有的輸入?yún)?shù)置于輸出參數(shù)之前. 特別要注意, 在加入新參數(shù)時(shí)不要因?yàn)樗鼈兪切聟?shù)就置于參數(shù)列表最后, 而是仍然要按照前述的規(guī)則, 即將新的輸入?yún)?shù)也置于輸出參數(shù)之前.
    的頭像 發(fā)表于 09-27 18:06 ?2674次閱讀

    Google編程風(fēng)格指南(四)

    用于定義移動(dòng)構(gòu)造函數(shù) (使用類(lèi)的右值引用進(jìn)行構(gòu)造的函數(shù)) 使得移動(dòng)一個(gè)值而非拷貝之成為可能. 例如, 如果 v1 是一個(gè) vector, 則 auto v2(std::move(v1)) 將很可能不再進(jìn)行大量的數(shù)據(jù)復(fù)制而只是簡(jiǎn)單地進(jìn)行指針操作, 在某些情況下這將帶來(lái)大幅度的性能提升.
    的頭像 發(fā)表于 09-27 18:08 ?3008次閱讀

    Google編程風(fēng)格指南(五)

    所有具有靜態(tài)存儲(chǔ)類(lèi)型的變量 (例如靜態(tài)變量或全局變量, 參見(jiàn) 存儲(chǔ)類(lèi)型) 都應(yīng)當(dāng)以此方式命名. 對(duì)于其他存儲(chǔ)類(lèi)型的變量, 如自動(dòng)變量等, 這條規(guī)則是可選的. 如果不采用這條規(guī)則, 就按照一般的變量命名規(guī)則.
    的頭像 發(fā)表于 09-27 18:15 ?2609次閱讀

    Google編程風(fēng)格指南(六)

    即使是英文, 也不應(yīng)將用戶(hù)界面的文本硬編碼到源代碼中, 因此非 ASCII 字符應(yīng)當(dāng)很少被用到. 特殊情況下可以適當(dāng)包含此類(lèi)字符. 例如, 代碼分析外部數(shù)據(jù)文件時(shí), 可以適當(dāng)硬編碼數(shù)據(jù)文件中作為分隔符的非 ASCII 字符串; 更常見(jiàn)的是 (不需要本地化的) 單元測(cè)試代碼可能包含非 ASCII 字符串. 此類(lèi)情況下, 應(yīng)使用 UTF-8 編碼, 因?yàn)楹芏喙ぞ叨伎梢岳斫夂吞幚?UTF-8 編碼.
    的頭像 發(fā)表于 09-27 18:18 ?2872次閱讀

    Google C++編程風(fēng)格指南PDF版免費(fèi)下載

    Google的項(xiàng)目大多使用C++開(kāi)發(fā)。每一個(gè)C++程序員也都知道, C++具有很多強(qiáng)大的語(yǔ)言特性,但這種強(qiáng)大不可避免的導(dǎo)致它的復(fù)雜,而復(fù)雜性會(huì)使得代碼更容易出現(xiàn)bug.難于閱讀和維護(hù)。
    發(fā)表于 03-06 08:00 ?0次下載
    <b class='flag-5'>Google</b> C++<b class='flag-5'>編程</b><b class='flag-5'>風(fēng)格</b><b class='flag-5'>指南</b>PDF版免費(fèi)下載

    Google C++編程風(fēng)格指南PDF電子書(shū)免費(fèi)下載

    Google 的開(kāi)源項(xiàng)目大多使用 C++開(kāi)發(fā)。每一個(gè) C++程序員也都知道,C++具有很多強(qiáng)大的語(yǔ)言特性,但這種強(qiáng)大不可避免的導(dǎo)致它的復(fù)雜,這種復(fù)雜會(huì)使得代碼更易于出現(xiàn) bug、難于閱讀和維護(hù)。本
    發(fā)表于 12-12 08:00 ?1次下載
    <b class='flag-5'>Google</b> C++<b class='flag-5'>編程</b><b class='flag-5'>風(fēng)格</b><b class='flag-5'>指南</b>PDF電子書(shū)免費(fèi)下載

    Verilog HIDL的RTL設(shè)計(jì)風(fēng)格指南資源下載

    Verilog HIDL的RTL設(shè)計(jì)風(fēng)格指南資源下載
    發(fā)表于 04-13 10:09 ?9次下載

    西門(mén)子S7-1200和S7-1500編程風(fēng)格指南

    西門(mén)子S7-1200和S7-1500編程風(fēng)格指南分享
    發(fā)表于 08-17 17:30 ?22次下載

    Google Python代碼風(fēng)格指南

    1 背景 Python是谷歌主要使用的動(dòng)態(tài)語(yǔ)言,本風(fēng)格指導(dǎo)列舉了使用Python編程時(shí)應(yīng)該做和不該做的事項(xiàng)(dos nothing on first line # 縮進(jìn)4個(gè)空格,首行括號(hào)后無(wú)內(nèi)容
    的頭像 發(fā)表于 11-03 10:20 ?3277次閱讀
    主站蜘蛛池模板: 久久五月网| 日本一线a视频免费观看 | 国产稀缺精品盗摄盗拍 | 国产免费成人在线视频 | 亚洲第一视频在线播放 | 日韩成a人片在线观看日本 日韩成人黄色 | 二区三区在线观看 | 亚洲综合天堂网 | 全亚洲最大的777io影院 | 无遮挡很爽很污很黄的网站w | 亚洲爱婷婷色婷婷五月 | 国产欧美亚洲精品第二区首页 | 久久天天躁狠狠躁夜夜 | a级毛片毛片免费很很综合 a级男女性高爱潮高清试 | 国产精品秒播无毒不卡 | 四虎影视大全免费入口 | 国产看片视频 | 午夜精品网 | 免费深夜视频 | 天天操夜夜操 | 免费一级特黄特色大片在线观看看 | videossexotv极度另类高清 | 亚洲国产情侣偷自在线二页 | 在线h网站| 日本久久综合视频 | 岛国毛片在线观看 | 黑人边吃奶边扎下面激情视频 | 一级毛片在播放免费 | 亚洲美女啪啪 | 77788色淫网站女女免费视频 | 天天爽夜夜春 | 韩国中文字幕在线观看 | 又粗又硬又爽又黄毛片 | 欧美性xxxx巨大黑人猛 | 国产色婷婷精品免费视频 | 亚洲电影免费 | 97成人在线视频 | 久久伊人草 | 日本黄色小说视频 | 日本一区二区在线不卡 | 4虎影视国产在线观看精品 4虎影院永久地址www |