diff --git a/google-cpp-styleguide/classes.rst b/google-cpp-styleguide/classes.rst
index 8c1db196..4399d9b8 100644
--- a/google-cpp-styleguide/classes.rst
+++ b/google-cpp-styleguide/classes.rst
@@ -8,7 +8,7 @@
.. tip::
- 不要在建構子中進行複雜的初始化 (尤其是那些有可能失敗或者需要呼叫虛函數的初始化).
+ 不要在建構子中進行複雜的初始化 (尤其是那些有可能失敗或者需要呼叫虛函式的初始化).
定義:
@@ -26,24 +26,24 @@
- 操作失敗會造成對象初始化失敗,進入不確定狀態.
- - 如果在建構子內呼叫了自身的虛函數, 這類呼叫是不會重定向到子類的虛函數實現. 即使當前沒有子類化實現, 將來仍是隱患.
+ - 如果在建構子內呼叫了自身的虛函式, 這類呼叫是不會重定向到子類的虛函式實作. 即使當前沒有子類化實作, 將來仍是隱患.
- - 如果有人創建該類型的全域變數 (雖然違背了上節提到的規則), 建構子將先 ``main()`` 一步被呼叫, 有可能破壞建構函數中暗含的假設條件. 例如, `gflags `_ 尚未初始化.
+ - 如果有人創建該類型的全域變數 (雖然違背了上節提到的規則), 建構子將先 ``main()`` 一步被呼叫, 有可能破壞建構函式中暗含的假設條件. 例如, `gflags `_ 尚未初始化.
結論:
- 建構子不得呼叫虛函數, 或嘗試報告一個非致命錯誤. 如果對象需要進行有意義的 (non-trivial) 初始化, 考慮使用明確的 Init() 方法或使用工廠模式.
+ 建構子不得呼叫虛函式, 或嘗試報告一個非致命錯誤. 如果對象需要進行有意義的 (non-trivial) 初始化, 考慮使用明確的 Init() 方法或使用工廠模式.
3.2. 初始化
~~~~~~~~~~~~~~~~~~~~
.. tip::
- 如果類中定義了成員變數, 則必須在類中為每個類提供初始化函數或定義一個建構子. 若未宣告建構函數, 則編譯器會生成一個默認的構造函數, 這有可能導致某些成員未被初始化或被初始化為不恰當的值.
+ 如果類中定義了成員變數, 則必須在類中為每個類提供初始化函式或定義一個建構子. 若未宣告建構函式, 則編譯器會生成一個默認的構造函式, 這有可能導致某些成員未被初始化或被初始化為不恰當的值.
定義:
- ``new`` 一個不帶參數的類對象時, 會呼叫這個類的默認建構子. 用 ``new[]`` 創建陣列時, 默認建構函數則總是被呼叫. 在類成員裡面進行初始化是指宣告一個成員變數的時候使用一個結構例如 ``int _count = 17`` 或者 ``string _name{"abc"}`` 來替代 ``int _count`` 或者 ``string _name`` 這樣的形式.
+ ``new`` 一個不帶參數的類對象時, 會呼叫這個類的默認建構子. 用 ``new[]`` 創建陣列時, 默認建構函式則總是被呼叫. 在類成員裡面進行初始化是指宣告一個成員變數的時候使用一個結構例如 ``int _count = 17`` 或者 ``string _name{"abc"}`` 來替代 ``int _count`` 或者 ``string _name`` 這樣的形式.
優點:
@@ -53,15 +53,15 @@
對程式碼編寫者來說, 這是多餘的工作.
- 如果一個成員變數在宣告時初始化又在建構子中初始化, 有可能造成混亂, 因為建構函數中的值會覆蓋掉宣告中的值.
+ 如果一個成員變數在宣告時初始化又在建構子中初始化, 有可能造成混亂, 因為建構函式中的值會覆蓋掉宣告中的值.
結論:
簡單的初始化用類成員初始化完成, 尤其是當一個成員變數要在多個建構子里用相同的方式初始化的時候.
- 如果你的類中有成員變數沒有在類裡面進行初始化, 而且沒有提供其它建構子, 你必須定義一個 (不帶參數的) 默認建構函數. 把對象的內部狀態初始化成一致 / 有效的值無疑是更合理的方式.
+ 如果你的類中有成員變數沒有在類裡面進行初始化, 而且沒有提供其它建構子, 你必須定義一個 (不帶參數的) 默認建構函式. 把對象的內部狀態初始化成一致 / 有效的值無疑是更合理的方式.
- 這麼做的原因是: 如果你沒有提供其它建構子, 又沒有定義默認建構函數, 編譯器將為你自動生成一個. 編譯器生成的構造函數並不會對對象進行合理的初始化.
+ 這麼做的原因是: 如果你沒有提供其它建構子, 又沒有定義默認建構函式, 編譯器將為你自動生成一個. 編譯器生成的構造函式並不會對對象進行合理的初始化.
如果你定義的類繼承現有類, 而你又沒有增加新的成員變數, 則不需要為新類定義默認建構子.
@@ -73,9 +73,9 @@
定義:
- 通常, 如果建構子只有一個參數, 可看成是一種隱式轉換. 打個比方, 如果你定義了 ``Foo::Foo(string name)``, 接著把一個字符串傳給一個以 ``Foo`` 對象為參數的函數, 建構函數 ``Foo::Foo(string name)`` 將被呼叫, 並將該字符串轉換為一個 ``Foo`` 的臨時對像傳給呼叫函數. 看上去很方便, 但如果你並不希望如此通過轉換生成一個新對象的話, 麻煩也隨之而來. 為避免構造函數被呼叫造成隱式轉換, 可以將其宣告為 ``explicit``.
+ 通常, 如果建構子只有一個參數, 可看成是一種隱式轉換. 打個比方, 如果你定義了 ``Foo::Foo(string name)``, 接著把一個字符串傳給一個以 ``Foo`` 對象為參數的函式, 建構函式 ``Foo::Foo(string name)`` 將被呼叫, 並將該字符串轉換為一個 ``Foo`` 的臨時對像傳給呼叫函式. 看上去很方便, 但如果你並不希望如此通過轉換生成一個新對象的話, 麻煩也隨之而來. 為避免構造函式被呼叫造成隱式轉換, 可以將其宣告為 ``explicit``.
- 除單參數建構子外, 這一規則也適用於除第一個參數以外的其他參數都具有默認參數的建構函數, 例如 Foo::Foo(string name, int id = 42).
+ 除單參數建構子外, 這一規則也適用於除第一個參數以外的其他參數都具有默認參數的建構函式, 例如 Foo::Foo(string name, int id = 42).
優點:
@@ -87,7 +87,7 @@
結論:
- 所有單參數建構子都必須是顯式的. 在類定義中, 將關鍵字 ``explicit`` 加到單參數建構函數前: ``explicit Foo(string name);``
+ 所有單參數建構子都必須是顯式的. 在類定義中, 將關鍵字 ``explicit`` 加到單參數建構函式前: ``explicit Foo(string name);``
例外: 在極少數情況下, 拷貝建構子可以不宣告成 ``explicit``. 作為其它類的透明包裝器的類也是特例之一. 類似的例外情況應在註解中明確說明.
@@ -106,36 +106,36 @@
.. tip::
- 如果你的類型需要, 就讓它們支持拷貝 / 移動. 否則, 就把隱式產生的拷貝和移動函數禁用.
+ 如果你的類型需要, 就讓它們支持拷貝 / 移動. 否則, 就把隱式產生的拷貝和移動函式禁用.
定義:
可拷貝類型允許對象在初始化時得到來自相同類型的另一對象的值, 或在賦值時被賦予相同類型的另一對象的值, 同時不改變源對象的值. 對於使用者定義的類型, 拷貝操作一般通過拷貝建構子與拷貝賦值操作符定義. string 類型就是一個可拷貝類型的例子.
- 可移動類型允許對象在初始化時得到來自相同類型的臨時對象的值, 或在賦值時被賦予相同類型的臨時對象的值 (因此所有可拷貝對象也是可移動的). std::unique_ptr 就是一個可移動但不可複製的對象的例子. 對於使用者定義的類型, 移動操作一般是通過移動建構子和移動賦值操作符實現的.
+ 可移動類型允許對象在初始化時得到來自相同類型的臨時對象的值, 或在賦值時被賦予相同類型的臨時對象的值 (因此所有可拷貝對象也是可移動的). std::unique_ptr 就是一個可移動但不可複製的對象的例子. 對於使用者定義的類型, 移動操作一般是通過移動建構子和移動賦值操作符實作的.
拷貝 / 移動建構子在某些情況下會被編譯器隱式呼叫. 例如, 通過傳值的方式傳遞對象.
優點:
- 可移動及可拷貝類型的對象可以通過傳值的方式進行傳遞或者返回, 這使得 API 更簡單, 更安全也更通用. 與傳指標和引用不同, 這樣的傳遞不會造成所有權, 生命週期, 可變性等方面的混亂, 也就沒必要在協議中予以明確. 這同時也防止了客戶端與實現在非作用域內的交互, 使得它們更容易被理解與維護. 這樣的對象可以和需要傳值操作的通用 API 一起使用, 例如大多數容器.
+ 可移動及可拷貝類型的對象可以通過傳值的方式進行傳遞或者返回, 這使得 API 更簡單, 更安全也更通用. 與傳指標和引用不同, 這樣的傳遞不會造成所有權, 生命週期, 可變性等方面的混亂, 也就沒必要在協議中予以明確. 這同時也防止了客戶端與實作在非作用域內的交互, 使得它們更容易被理解與維護. 這樣的對象可以和需要傳值操作的通用 API 一起使用, 例如大多數容器.
- 拷貝 / 移動建構子與賦值操作一般來說要比它們的各種替代方案, 比如 Clone(), CopyFrom() or Swap(), 更容易定義, 因為它們能通過編譯器產生, 無論是隱式的還是通過 = 默認. 這種方式很簡潔, 也保證所有數據成員都會被複製. 拷貝與移動建構函數一般也更高效, 因為它們不需要堆的分配或者是單獨的初始化和賦值步驟, 同時, 對於類似省略不必要的拷貝這樣的優化它們也更加合適.
+ 拷貝 / 移動建構子與賦值操作一般來說要比它們的各種替代方案, 比如 Clone(), CopyFrom() or Swap(), 更容易定義, 因為它們能通過編譯器產生, 無論是隱式的還是通過 = 默認. 這種方式很簡潔, 也保證所有數據成員都會被複製. 拷貝與移動建構函式一般也更高效, 因為它們不需要堆的分配或者是單獨的初始化和賦值步驟, 同時, 對於類似省略不必要的拷貝這樣的優化它們也更加合適.
移動操作允許隱式且高效地將源數據轉移出右值對象. 這有時能讓程式碼風格更加清晰.
缺點:
- 許多類型都不需要拷貝, 為它們提供拷貝操作會讓人迷惑, 也顯得荒謬而不合理. 為父類別提供拷貝 / 賦值操作是有害的, 因為在使用它們時會造成對象切割. 默認的或者隨意的拷貝操作實現可能是不正確的, 這往往導致令人困惑並且難以診斷出的錯誤.
+ 許多類型都不需要拷貝, 為它們提供拷貝操作會讓人迷惑, 也顯得荒謬而不合理. 為父類別提供拷貝 / 賦值操作是有害的, 因為在使用它們時會造成對象切割. 默認的或者隨意的拷貝操作實作可能是不正確的, 這往往導致令人困惑並且難以診斷出的錯誤.
拷貝建構子是隱式呼叫的, 也就是說, 這些呼叫很容易被忽略. 這會讓人迷惑, 尤其是對那些所用的語言約定或強制要求傳引用的開發者來說更是如此. 同時, 這從一定程度上說會鼓勵過度拷貝, 從而導致性能上的問題.
結論:
- 如果需要就讓你的類型可拷貝 / 可移動. 作為一個經驗法則, 如果對於你的使用者來說這個拷貝操作不是一眼就能看出來的, 那就不要把類型設置為可拷貝. 如果讓類型可拷貝, 一定要同時給出拷貝建構子和賦值操作的定義. 如果讓類型可拷貝, 同時移動操作的效率高於拷貝操作, 那麼就把移動的兩個操作 (移動建構函數和賦值操作) 也給出定義. 如果類型不可拷貝, 但是移動操作的正確性對用戶顯然可見, 那麼把這個類型設置為只可移動並定義移動的兩個操作.
+ 如果需要就讓你的類型可拷貝 / 可移動. 作為一個經驗法則, 如果對於你的使用者來說這個拷貝操作不是一眼就能看出來的, 那就不要把類型設置為可拷貝. 如果讓類型可拷貝, 一定要同時給出拷貝建構子和賦值操作的定義. 如果讓類型可拷貝, 同時移動操作的效率高於拷貝操作, 那麼就把移動的兩個操作 (移動建構函式和賦值操作) 也給出定義. 如果類型不可拷貝, 但是移動操作的正確性對用戶顯然可見, 那麼把這個類型設置為只可移動並定義移動的兩個操作.
建議通過 ``= default`` 定義拷貝和移動操作. 定義非默認的移動操作目前需要例外. 時刻記得檢測默認操作的正確性.
- 由於存在對象切割的風險, 不要為任何有可能有派生類的對象提供賦值操作或者拷貝 / 移動建構子 (當然也不要繼承有這樣的成員函數的類). 如果你的父類別需要可複製屬性, 請提供一個 ``public virtual Clone()`` 和一個 ``protected`` 的拷貝建構函數以供派生類實現.
+ 由於存在對象切割的風險, 不要為任何有可能有派生類的對象提供賦值操作或者拷貝 / 移動建構子 (當然也不要繼承有這樣的成員函式的類). 如果你的父類別需要可複製屬性, 請提供一個 ``public virtual Clone()`` 和一個 ``protected`` 的拷貝建構函式以供派生類實作.
如果你的類不需要拷貝 / 移動操作, 請顯式地通過 ``= delete`` 或其他手段禁用之.
@@ -151,7 +151,7 @@
定義:
- 委派和繼承建構子是由 C++11 引進為了減少建構函數重複程式碼而開發的兩種不同的特性. 通過特殊的初始化列表語法, 委派構造函數允許類的一個構造函數呼叫其他的構造函數. 例如:
+ 委派和繼承建構子是由 C++11 引進為了減少建構函式重複程式碼而開發的兩種不同的特性. 通過特殊的初始化列表語法, 委派構造函式允許類的一個構造函式呼叫其他的構造函式. 例如:
.. code-block:: c++
@@ -161,7 +161,7 @@
X::X() : X("") { }
- 繼承建構子允許派生類直接呼叫父類別的建構函數, 一如繼承父類別的其他成員函數, 而無需重新宣告. 當父類別擁有多個構造函數時這一功能尤其有用. 例如:
+ 繼承建構子允許派生類直接呼叫父類別的建構函式, 一如繼承父類別的其他成員函式, 而無需重新宣告. 當父類別擁有多個構造函式時這一功能尤其有用. 例如:
.. code-block:: c++
@@ -178,7 +178,7 @@
using Base::Base; // Base's constructors are redeclared here.
};
- 如果派生類的建構子只是呼叫父類別的建構函數而沒有其他行為時, 這一功能特別有用.
+ 如果派生類的建構子只是呼叫父類別的建構函式而沒有其他行為時, 這一功能特別有用.
優點:
@@ -187,12 +187,12 @@
缺點:
- 使用輔助函數可以預估出委派建構子的行為.
+ 使用輔助函式可以預估出委派建構子的行為.
如果派生類和父類別相比引入了新的成員變數, 繼承建構子就會讓人迷惑, 因為父類別並不知道這些新的成員變量的存在.
結論:
- 只在能夠減少冗余程式碼, 提高可讀性的前提下使用委派和繼承建構子. 如果派生類有新的成員變數, 那麼使用繼承建構函數時要小心. 如果在派生類中對成員變量使用了類內部初始化的話, 繼承構造函數還是適用的.
+ 只在能夠減少冗余程式碼, 提高可讀性的前提下使用委派和繼承建構子. 如果派生類有新的成員變數, 那麼使用繼承建構函式時要小心. 如果在派生類中對成員變量使用了類內部初始化的話, 繼承構造函式還是適用的.
3.6. 結構體 VS. 類
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -205,11 +205,11 @@
在 C++ 中 struct 和 class 關鍵字幾乎含義一樣. 我們為這兩個關鍵字添加我們自己的語義理解, 以便未定義的數據類型選擇合適的關鍵字.
- struct 用來定義包含數據的被動式對象, 也可以包含相關的常數, 但除了存取數據成員之外, 沒有別的函數功能. 並且存取功能是通過直接訪問位域, 而非函數呼叫. 除了建構子, 解構子, Initialize(), Reset(), Validate() 等類似的函數外, 不能提供其它功能的函數.
+ struct 用來定義包含數據的被動式對象, 也可以包含相關的常數, 但除了存取數據成員之外, 沒有別的函式功能. 並且存取功能是通過直接訪問位域, 而非函式呼叫. 除了建構子, 解構子, Initialize(), Reset(), Validate() 等類似的函式外, 不能提供其它功能的函式.
- 如果需要更多的函數功能, class 更適合. 如果拿不準, 就用 class.
+ 如果需要更多的函式功能, class 更適合. 如果拿不準, 就用 class.
- 為了和 STL 保持一致, 對於仿函數和 trait 特性可以不用 class 而是使用 struct.
+ 為了和 STL 保持一致, 對於仿函式和 trait 特性可以不用 class 而是使用 struct.
注意: 類和結構體的成員變數使用不同的命名規則.
@@ -224,25 +224,25 @@
定義:
- 當子類繼承父類別時, 子類包含了父類別所有數據及操作的定義. C++ 實踐中, 繼承主要用於兩種場合: 實現繼承 (implementation inheritance), 子類繼承父類別的實現程式碼; 介面繼承 (interface inheritance), 子類僅繼承父類的方法名稱.
+ 當子類繼承父類別時, 子類包含了父類別所有數據及操作的定義. C++ 實踐中, 繼承主要用於兩種場合: 實作繼承 (implementation inheritance), 子類繼承父類別的實作程式碼; 介面繼承 (interface inheritance), 子類僅繼承父類的方法名稱.
優點:
- 實現繼承通過原封不動的復用父類別程式碼減少了程式碼量. 由於繼承是在編譯時宣告, 開發者和編譯器都可以理解相應操作並發現錯誤. 從程式撰寫角度而言, 介面繼承是用來強制類輸出特定的 API. 在類沒有實現 API 中某個必須的方法時, 編譯器同樣會發現並報告錯誤.
+ 實作繼承通過原封不動的復用父類別程式碼減少了程式碼量. 由於繼承是在編譯時宣告, 開發者和編譯器都可以理解相應操作並發現錯誤. 從程式撰寫角度而言, 介面繼承是用來強制類輸出特定的 API. 在類沒有實作 API 中某個必須的方法時, 編譯器同樣會發現並報告錯誤.
缺點:
- 對於實現繼承, 由於子類的實現程式碼散佈在父類別和子類間之間, 要理解其實現變得更加困難. 子類不能重寫父類的非虛函數, 當然也就不能修改其實現. 父類別也可能定義了一些數據成員, 還要區分父類別的實際佈局.
+ 對於實作繼承, 由於子類的實作程式碼散佈在父類別和子類間之間, 要理解其實作變得更加困難. 子類不能重寫父類的非虛函式, 當然也就不能修改其實作. 父類別也可能定義了一些數據成員, 還要區分父類別的實際佈局.
結論:
所有繼承必須是 ``public`` 的. 如果你想使用私有繼承, 你應該替換成把父類別的實例作為成員對象的方式.
- 不要過度使用實現繼承. 組合常常更合適一些. 盡量做到只在 "是一個" ("is-a", YuleFox 注: 其他 "has-a" 情況下請使用組合) 的情況下使用繼承: 如果 ``Bar`` 的確 "是一種" Foo, ``Bar`` 才能繼承 ``Foo``.
+ 不要過度使用實作繼承. 組合常常更合適一些. 盡量做到只在 "是一個" ("is-a", YuleFox 注: 其他 "has-a" 情況下請使用組合) 的情況下使用繼承: 如果 ``Bar`` 的確 "是一種" Foo, ``Bar`` 才能繼承 ``Foo``.
- 必要的話, 解構子宣告為 ``virtual``. 如果你的類有虛函數, 則解構子也應該為虛函數. 注意 `數據成員在任何情況下都必須是私有的 <....>`_.
+ 必要的話, 解構子宣告為 ``virtual``. 如果你的類有虛函式, 則解構子也應該為虛函式. 注意 `數據成員在任何情況下都必須是私有的 <....>`_.
- 當重載一個虛函數, 在衍生類中把它明確的宣告為 ``virtual``. 理論依據: 如果省略 ``virtual`` 關鍵字, 程式碼閱讀者不得不檢查所有父類別, 以判斷該函數是否是虛函數.
+ 當重載一個虛函式, 在衍生類中把它明確的宣告為 ``virtual``. 理論依據: 如果省略 ``virtual`` 關鍵字, 程式碼閱讀者不得不檢查所有父類別, 以判斷該函式是否是虛函式.
.. _multiple-inheritance:
@@ -251,19 +251,19 @@
.. tip::
- 真正需要用到多重實現繼承的情況少之又少. 只在以下情況我們才允許多重繼承: 最多只有一個父類別是非抽像類; 其它父類別都是以 ``Interface`` 為後綴的 :ref:`純介面類 `.
+ 真正需要用到多重實作繼承的情況少之又少. 只在以下情況我們才允許多重繼承: 最多只有一個父類別是非抽像類; 其它父類別都是以 ``Interface`` 為後綴的 :ref:`純介面類 `.
定義:
- 多重繼承允許子類擁有多個父類別. 要將作為 *純介面* 的父類別和具有 *實現* 的父類別區別開來.
+ 多重繼承允許子類擁有多個父類別. 要將作為 *純介面* 的父類別和具有 *實作* 的父類別區別開來.
優點:
- 相比單繼承 (見 :ref:`繼承 `), 多重實現繼承可以復用更多的程式碼.
+ 相比單繼承 (見 :ref:`繼承 `), 多重實作繼承可以復用更多的程式碼.
缺點:
- 真正需要用到多重 *實現* 繼承的情況少之又少. 多重實現繼承看上去是不錯的解決方案, 但你通常也可以找到一個更明確, 更清晰的不同解決方案.
+ 真正需要用到多重 *實作* 繼承的情況少之又少. 多重實作繼承看上去是不錯的解決方案, 但你通常也可以找到一個更明確, 更清晰的不同解決方案.
結論:
@@ -286,20 +286,20 @@
當一個類滿足以下要求時, 稱之為純介面:
- - 只有純虛函數 ("``=0``") 和靜態函數 (除了下文提到的解構子).
+ - 只有純虛函式 ("``=0``") 和靜態函式 (除了下文提到的解構子).
- 沒有非靜態數據成員.
- 沒有定義任何建構子. 如果有, 也不能帶有參數, 並且必須為 ``protected``.
- 如果它是一個子類, 也只能從滿足上述條件並以 ``Interface`` 為後綴的類繼承.
- 介面類不能被直接實例化, 因為它宣告了純虛函數. 為確保接口類的所有實現可被正確銷毀, 必須為之宣告虛解構子 (作為上述第 1 條規則的特例, 解構子不能是純虛函數). 具體細節可參考 Stroustrup 的 *The C++ Programming Language, 3rd edition* 第 12.4 節.
+ 介面類不能被直接實例化, 因為它宣告了純虛函式. 為確保接口類的所有實作可被正確銷毀, 必須為之宣告虛解構子 (作為上述第 1 條規則的特例, 解構子不能是純虛函式). 具體細節可參考 Stroustrup 的 *The C++ Programming Language, 3rd edition* 第 12.4 節.
優點:
- 以 ``Interface`` 為後綴可以提醒其他人不要為該介面類增加函數實現或非靜態數據成員. 這一點對於 :ref:`多重繼承 ` 尤其重要. 另外, 對於 Java 開發者來說, 接口的概念已是深入人心.
+ 以 ``Interface`` 為後綴可以提醒其他人不要為該介面類增加函式實作或非靜態數據成員. 這一點對於 :ref:`多重繼承 ` 尤其重要. 另外, 對於 Java 開發者來說, 接口的概念已是深入人心.
缺點:
- ``Interface`` 後綴增加了類名長度, 為閱讀和理解帶來不便. 同時,介面特性作為實現細節不應暴露給使用者.
+ ``Interface`` 後綴增加了類名長度, 為閱讀和理解帶來不便. 同時,介面特性作為實作細節不應暴露給使用者.
結論:
@@ -318,7 +318,7 @@
優點:
- 使程式碼看上去更加直觀, 類表現的和內建類型 (如 ``int``) 行為一致. 重載運算子使 ``Equals()``, ``Add()`` 等函數名黯然失色. 為了使一些樣板函數正確工作, 你可能必須定義操作符.
+ 使程式碼看上去更加直觀, 類表現的和內建類型 (如 ``int``) 行為一致. 重載運算子使 ``Equals()``, ``Add()`` 等函式名黯然失色. 為了使一些樣板函式正確工作, 你可能必須定義操作符.
缺點:
@@ -332,26 +332,26 @@
結論:
- 一般不要重載運算子. 尤其是賦值操作 (``operator=``) 比較詭異, 應避免重載. 如果需要的話, 可以定義類似 ``Equals()``, ``CopyFrom()`` 等函數.
+ 一般不要重載運算子. 尤其是賦值操作 (``operator=``) 比較詭異, 應避免重載. 如果需要的話, 可以定義類似 ``Equals()``, ``CopyFrom()`` 等函式.
- 然而, 極少數情況下可能需要重載運算子以便與樣板或 "標準" C++ 類互操作 (如 ``operator<<(ostream&, const T&)``). 只有被證明是完全合理的才能重載, 但你還是要盡可能避免這樣做. 尤其是不要僅僅為了在 STL 容器中用作鍵值就重載 ``operator==`` 或 ``operator<``; 相反, 你應該在宣告容器的時候, 創建相等判斷和大小比較的仿函數類型.
+ 然而, 極少數情況下可能需要重載運算子以便與樣板或 "標準" C++ 類互操作 (如 ``operator<<(ostream&, const T&)``). 只有被證明是完全合理的才能重載, 但你還是要盡可能避免這樣做. 尤其是不要僅僅為了在 STL 容器中用作鍵值就重載 ``operator==`` 或 ``operator<``; 相反, 你應該在宣告容器的時候, 創建相等判斷和大小比較的仿函式類型.
有些 STL 算法確實需要重載 ``operator==`` 時, 你可以這麼做, 記得別忘了在文檔中說明原因.
- 參考 :ref:`拷貝建構子 ` 和 :ref:`函數重載 `.
+ 參考 :ref:`拷貝建構子 ` 和 :ref:`函式重載 `.
3.11. 存取控制
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. tip::
- 將 *所有* 數據成員宣告為 ``private``, 並根據需要提供相應的存取函數. 例如, 某個名為 ``foo_`` 的變數, 其取值函數是 ``foo()``. 還可能需要一個賦值函數 ``set_foo()``.
+ 將 *所有* 數據成員宣告為 ``private``, 並根據需要提供相應的存取函式. 例如, 某個名為 ``foo_`` 的變數, 其取值函式是 ``foo()``. 還可能需要一個賦值函式 ``set_foo()``.
特例是, 靜態常數數據成員 (一般寫做 kFoo) 不需要是私有成員.
- 一般在標頭檔中把存取函數定義成內聯函數.
+ 一般在標頭檔中把存取函式定義成內聯函式.
- 參考 :ref:`繼承 ` 和 :ref:`函數命名 `
+ 參考 :ref:`繼承 ` 和 :ref:`函式命名 `
.. _declaration-order:
@@ -360,7 +360,7 @@
.. tip::
- 在類中使用特定的宣告順序: ``public:`` 在 ``private:`` 之前, 成員函數在數據成員 (變數) 前;
+ 在類中使用特定的宣告順序: ``public:`` 在 ``private:`` 之前, 成員函式在數據成員 (變數) 前;
類的訪問控制區段的宣告順序依次為: ``public:``, ``protected:``, ``private:``. 如果某區段沒內容, 可以不宣告.
@@ -370,40 +370,40 @@
- 常數
- 建構子
- 解構子
- - 成員函數, 含靜態成員函數
+ - 成員函式, 含靜態成員函式
- 數據成員, 含靜態數據成員
友元宣告應該放在 private 區段. 如果用巨集 DISALLOW_COPY_AND_ASSIGN 禁用拷貝和賦值, 應當將其置於 private 區段的末尾, 也即整個類宣告的末尾. 參見可拷貝類型和可移動類型.
-``.cc`` 文件中函數的定義應盡可能和宣告順序一致.
+``.cc`` 文件中函式的定義應盡可能和宣告順序一致.
-不要在類定義中內聯大型函數. 通常, 只有那些沒有特別意義或性能要求高, 並且是比較短小的函數才能被定義為內聯函數. 更多細節參考 :ref:`內聯函數 `.
+不要在類定義中內聯大型函式. 通常, 只有那些沒有特別意義或性能要求高, 並且是比較短小的函式才能被定義為內聯函式. 更多細節參考 :ref:`內聯函式 `.
-3.12. 編寫簡短函數
+3.12. 編寫簡短函式
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. tip::
- 傾向編寫簡短, 凝練的函數.
+ 傾向編寫簡短, 凝練的函式.
-我們承認長函數有時是合理的, 因此並不硬性限制函數的長度. 如果函數超過 40 行, 可以思索一下能不能在不影響程式結構的前提下對其進行分割.
+我們承認長函式有時是合理的, 因此並不硬性限制函式的長度. 如果函式超過 40 行, 可以思索一下能不能在不影響程式結構的前提下對其進行分割.
-即使一個長函數現在工作的非常好, 一旦有人對其修改, 有可能出現新的問題. 甚至導致難以發現的 bug. 使函數盡量簡短, 便於他人閱讀和修改程式碼.
+即使一個長函式現在工作的非常好, 一旦有人對其修改, 有可能出現新的問題. 甚至導致難以發現的 bug. 使函式盡量簡短, 便於他人閱讀和修改程式碼.
-在處理程式碼時, 你可能會發現複雜的長函數. 不要害怕修改現有程式碼: 如果證實這些程式碼使用 / 調試困難, 或者你需要使用其中的一小段程式碼, 考慮將其分割為更加簡短並易於管理的若干函數.
+在處理程式碼時, 你可能會發現複雜的長函式. 不要害怕修改現有程式碼: 如果證實這些程式碼使用 / 調試困難, 或者你需要使用其中的一小段程式碼, 考慮將其分割為更加簡短並易於管理的若干函式.
譯者 (YuleFox) 筆記
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#. 不在建構子中做太多邏輯相關的初始化;
-#. 編譯器提供的默認建構子不會對變數進行初始化, 如果定義了其他建構函數, 編譯器不再提供, 需要編碼者自行提供默認構造函數;
+#. 編譯器提供的默認建構子不會對變數進行初始化, 如果定義了其他建構函式, 編譯器不再提供, 需要編碼者自行提供默認構造函式;
#. 為避免隱式轉換, 需將單參數建構子宣告為 ``explicit``;
-#. 為避免拷貝建構子, 賦值操作的濫用和編譯器自動生成, 可將其宣告為 ``private`` 且無需實現;
+#. 為避免拷貝建構子, 賦值操作的濫用和編譯器自動生成, 可將其宣告為 ``private`` 且無需實作;
#. 僅在作為數據集合時使用 ``struct``;
-#. 組合 > 實現繼承 > 介面繼承 > 私有繼承, 子類重載的虛函數也要宣告 ``virtual`` 關鍵字, 雖然編譯器允許不這樣做;
-#. 避免使用多重繼承, 使用時, 除一個父類別含有實現外, 其他父類別均為純介面;
-#. 介面類類名以 ``Interface`` 為後綴, 除提供帶實現的虛解構子, 靜態成員函數外, 其他均為純虛函數, 不定義非靜態數據成員, 不提供建構子, 提供的話,宣告為 ``protected``;
+#. 組合 > 實作繼承 > 介面繼承 > 私有繼承, 子類重載的虛函式也要宣告 ``virtual`` 關鍵字, 雖然編譯器允許不這樣做;
+#. 避免使用多重繼承, 使用時, 除一個父類別含有實作外, 其他父類別均為純介面;
+#. 介面類類名以 ``Interface`` 為後綴, 除提供帶實作的虛解構子, 靜態成員函式外, 其他均為純虛函式, 不定義非靜態數據成員, 不提供建構子, 提供的話,宣告為 ``protected``;
#. 為降低複雜性, 盡量不重載操作符, 樣板, 標準類中使用時提供文檔說明;
-#. 存取函數一般內聯在標頭檔中;
+#. 存取函式一般內聯在標頭檔中;
#. 宣告次序: ``public`` -> ``protected`` -> ``private``;
-#. 函數體盡量短小, 緊湊, 功能單一;
+#. 函式體盡量短小, 緊湊, 功能單一;
diff --git a/google-cpp-styleguide/comments.rst b/google-cpp-styleguide/comments.rst
index 9a6cae68..4af40477 100644
--- a/google-cpp-styleguide/comments.rst
+++ b/google-cpp-styleguide/comments.rst
@@ -37,7 +37,7 @@
緊接著版權許可和作者信息之後, 每個文件都要用註解描述文件內容.
- 通常, ``.h`` 文件要對所宣告的類的功能和用法作簡單說明. ``.cc`` 文件通常包含了更多的實現細節或算法技巧討論, 如果你感覺這些實現細節或算法技巧討論對於理解 ``.h`` 文件有幫助, 可以將該註解挪到 ``.h``, 並在 ``.cc`` 中指出文檔在 ``.h``.
+ 通常, ``.h`` 文件要對所宣告的類的功能和用法作簡單說明. ``.cc`` 文件通常包含了更多的實作細節或算法技巧討論, 如果你感覺這些實作細節或算法技巧討論對於理解 ``.h`` 文件有幫助, 可以將該註解挪到 ``.h``, 並在 ``.cc`` 中指出文檔在 ``.h``.
不要簡單的在 ``.h`` 和 ``.cc`` 間複製註解. 這種偏離了註釋的實際意義.
@@ -66,25 +66,25 @@
如果類有任何同步前提, 文檔說明之. 如果該類的實例可被多線程訪問, 要特別注意文檔說明多線程環境下相關的規則和常數使用.
-7.4. 函數註解
+7.4. 函式註解
~~~~~~~~~~~~~~~~~~~~~~
.. tip::
- 函數宣告處註解描述函數功能; 定義處描述函數實現.
+ 函式宣告處註解描述函式功能; 定義處描述函式實作.
-函數宣告:
+函式宣告:
- 註解位於宣告之前, 對函數功能及用法進行描述. 註釋使用敘述式 ("Opens the file") 而非指令式 ("Open the file"); 註釋只是為了描述函數, 而不是命令函數做什麼. 通常, 註釋不會描述函數如何工作. 那是函數定義部分的事情.
+ 註解位於宣告之前, 對函式功能及用法進行描述. 註釋使用敘述式 ("Opens the file") 而非指令式 ("Open the file"); 註釋只是為了描述函式, 而不是命令函式做什麼. 通常, 註釋不會描述函式如何工作. 那是函式定義部分的事情.
- 函數宣告處註解的內容:
+ 函式宣告處註解的內容:
- - 函數的輸入輸出.
- - 對類成員函數而言: 函數呼叫期間對象是否需要保持引用參數, 是否會釋放這些參數.
- - 如果函數分配了空間, 需要由呼叫者釋放.
+ - 函式的輸入輸出.
+ - 對類成員函式而言: 函式呼叫期間對象是否需要保持引用參數, 是否會釋放這些參數.
+ - 如果函式分配了空間, 需要由呼叫者釋放.
- 參數是否可以為 ``NULL``.
- - 是否存在函數使用上的性能隱患.
- - 如果函數是可重入的, 其同步前提是什麼?
+ - 是否存在函式使用上的性能隱患.
+ - 如果函式是可重入的, 其同步前提是什麼?
舉例如下:
@@ -115,11 +115,11 @@
註解建構/解構子時, 切記讀程式碼的人知道構造/解構子是幹啥的, 所以 "destroys this object" 這樣的註釋是沒有意義的. 註明建構子對參數做了什麼 (例如, 是否取得指標所有權) 以及解構子清理了什麼. 如果都是些無關緊要的內容, 直接省掉註釋. 解構子前沒有註釋是很正常的.
-函數定義:
+函式定義:
- 每個函數定義時要用註解說明函數功能和實現要點. 比如說說你用的程式撰寫技巧, 實現的大致步驟, 或解釋如此實現的理由, 為什麼前半部分要加鎖而後半部分不需要.
+ 每個函式定義時要用註解說明函式功能和實作要點. 比如說說你用的程式撰寫技巧, 實作的大致步驟, 或解釋如此實作的理由, 為什麼前半部分要加鎖而後半部分不需要.
- *不要* 從 ``.h`` 文件或其他地方的函數宣告處直接複製註解. 簡要重述函數功能是可以的, 但註釋重點要放在如何實現上.
+ *不要* 從 ``.h`` 文件或其他地方的函式宣告處直接複製註解. 簡要重述函式功能是可以的, 但註釋重點要放在如何實作上.
7.5. 變數註解
~~~~~~~~~~~~~~~~~~~~~~
@@ -150,7 +150,7 @@
// The total number of tests cases that we run through in this regression test.
const int kNumTestCases = 6;
-7.6. 實現註解
+7.6. 實作註解
~~~~~~~~~~~~~~~~~~~~~~
.. tip::
@@ -182,7 +182,7 @@
if (mmap_budget >= data_size_ && !MmapData(mmap_chunk_bytes, mlock))
return; // Error already logged.
- 注意, 這裡用了兩段註解分別描述這段程式碼的作用, 和提示函數返回時錯誤已經被記入日誌.
+ 注意, 這裡用了兩段註解分別描述這段程式碼的作用, 和提示函式返回時錯誤已經被記入日誌.
如果你需要連續進行多行註解, 可以使之對齊獲得更好的可讀性:
@@ -198,7 +198,7 @@
NULL, true/false, 1, 2, 3...:
- 向函數傳入 ``NULL``, 布爾值或整數時, 要註解說明含義, 或使用常數讓程式碼望文知意. 例如, 對比:
+ 向函式傳入 ``NULL``, 布爾值或整數時, 要註解說明含義, 或使用常數讓程式碼望文知意. 例如, 對比:
.. warning::
.. code-block:: c++
diff --git a/google-cpp-styleguide/end.rst b/google-cpp-styleguide/end.rst
index f5391626..967cc9bc 100644
--- a/google-cpp-styleguide/end.rst
+++ b/google-cpp-styleguide/end.rst
@@ -7,6 +7,6 @@
編輯程式碼時, 花點時間看看專案中的其它程式碼, 並熟悉其風格. 如果其它程式碼中 ``if`` 語句使用空格, 那麼你也要使用. 如果其中的註解用星號 (*) 圍成一個盒子狀, 你同樣要這麼做.
-風格指南的重點在於提供一個通用的程式撰寫規範, 這樣大家可以把精力集中在實現內容而不是表現形式上. 我們展示了全域的風格規範, 但局部風格也很重要, 如果你在一個文件中新加的程式碼和原有程式碼風格相去甚遠, 這就破壞了文件本身的整體美觀, 也影響閱讀, 所以要盡量避免.
+風格指南的重點在於提供一個通用的程式撰寫規範, 這樣大家可以把精力集中在實作內容而不是表現形式上. 我們展示了全域的風格規範, 但局部風格也很重要, 如果你在一個文件中新加的程式碼和原有程式碼風格相去甚遠, 這就破壞了文件本身的整體美觀, 也影響閱讀, 所以要盡量避免.
好了, 關於編碼風格寫的夠多了; 程式碼本身才更有趣. 盡情享受吧!
diff --git a/google-cpp-styleguide/exceptions.rst b/google-cpp-styleguide/exceptions.rst
index a9e4a2b7..e6e9f038 100644
--- a/google-cpp-styleguide/exceptions.rst
+++ b/google-cpp-styleguide/exceptions.rst
@@ -35,7 +35,7 @@
在 Windows 上, 只有很少的一些情況下, 我們可以偶爾違反規則:
- - 通常我們 :ref:`禁止使用多重繼承 `, 但在使用 COM 和 ATL/WTL 類時可以使用多重繼承. 為了實現 COM 或 ATL/WTL 類/介面, 你可能不得不使用多重實現繼承.
+ - 通常我們 :ref:`禁止使用多重繼承 `, 但在使用 COM 和 ATL/WTL 類時可以使用多重繼承. 為了實作 COM 或 ATL/WTL 類/介面, 你可能不得不使用多重實作繼承.
- 雖然程式碼中不應該使用例外, 但是在 ATL 和部分 STL(包括 Visual C++ 的 STL) 中異常被廣泛使用. 使用 ATL 時, 應定義 ``_ATL_NO_EXCEPTIONS`` 以禁用異常. 你要研究一下是否能夠禁用 STL 的異常, 如果無法禁用, 啟用編譯器異常也可以. (注意這只是為了編譯 STL, 自己程式碼裡仍然不要含異常處理.)
diff --git a/google-cpp-styleguide/formatting.rst b/google-cpp-styleguide/formatting.rst
index c3d7cdab..b51476f1 100644
--- a/google-cpp-styleguide/formatting.rst
+++ b/google-cpp-styleguide/formatting.rst
@@ -60,14 +60,14 @@
我們使用空格縮排. 不要在程式碼中使用制符表. 你應該設置編輯器將制符表轉為空格.
-8.4. 函數宣告與定義
+8.4. 函式宣告與定義
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. tip::
- 返回類型和函數名在同一行, 參數也盡量放在同一行,如果放不下就對形參分行。
+ 返回類型和函式名在同一行, 參數也盡量放在同一行,如果放不下就對形參分行。
-函數看上去像這樣:
+函式看上去像這樣:
.. code-block:: c++
@@ -100,23 +100,23 @@
注意以下幾點:
- - 如果返回類型和函數名在一行放不下,分行。
+ - 如果返回類型和函式名在一行放不下,分行。
- - 如果返回類型那個與函數宣告或定義分行了,不要縮排。
+ - 如果返回類型那個與函式宣告或定義分行了,不要縮排。
- - 左圓括號總是和函數名在同一行;
+ - 左圓括號總是和函式名在同一行;
- - 函數名和左圓括號間沒有空格;
+ - 函式名和左圓括號間沒有空格;
- 圓括號與參數間沒有空格;
- 左大括號總在最後一個參數同一行的末尾處;
- - 如果其它風格規則允許的話,右大括號總是單獨位於函數最後一行,或者與左大括號同一行。
+ - 如果其它風格規則允許的話,右大括號總是單獨位於函式最後一行,或者與左大括號同一行。
- 右大括號和左大括號間總是有一個空格;
- - 函數宣告和定義中的所有形參必須有命名且一致;
+ - 函式宣告和定義中的所有形參必須有命名且一致;
- 所有形參應盡可能對齊;
@@ -124,7 +124,7 @@
- 換行後的參數保持 4 個空格的縮排;
-如果有些參數沒有用到, 在函數定義處將參數名註解起來:
+如果有些參數沒有用到, 在函式定義處將參數名註解起來:
.. code-block:: c++
@@ -147,7 +147,7 @@
.. code-block:: c++
- // 差 - 如果將來有人要實現,很難猜出變數是幹什麼用的。
+ // 差 - 如果將來有人要實作,很難猜出變數是幹什麼用的。
void Circle::Rotate(double) {}
8.5. Lambda 表達式
@@ -155,7 +155,7 @@
.. tip::
- 其它函數怎麼格式化形參和函數體,Lambda 表達式就怎麼格式化;捕獲列表同理。
+ 其它函式怎麼格式化形參和函式體,Lambda 表達式就怎麼格式化;捕獲列表同理。
若用引用捕獲,在變數名和 ``&`` 之間不留空格。
@@ -164,7 +164,7 @@
int x = 0;
auto add_to_x = [&x](int n) { x += n; };
- 短 lambda 就寫得和內聯函數一樣。
+ 短 lambda 就寫得和內聯函式一樣。
.. code-block:: c++
@@ -175,14 +175,14 @@
}),
digits.end());
-8.6. 函數呼叫
+8.6. 函式呼叫
~~~~~~~~~~~~~~~~~~~~~~
.. tip::
- 要麼一行寫完函數呼叫,要麼在圓括號裡對參數分行,要麼參數另起一行且縮排四格。如果沒有其它顧慮的話,盡可能精簡行數,比如把多個參數適當地放在同一行裡。
+ 要麼一行寫完函式呼叫,要麼在圓括號裡對參數分行,要麼參數另起一行且縮排四格。如果沒有其它顧慮的話,盡可能精簡行數,比如把多個參數適當地放在同一行裡。
- 函數呼叫遵循如下形式:
+ 函式呼叫遵循如下形式:
.. code-block:: c++
@@ -208,9 +208,9 @@
argument3, argument4);
}
- 把多個參數放在同一行,是為了減少函數呼叫所需的行數,除非影響到可讀性。有人認為把每個參數都獨立成行,不僅更好讀,而且方便編輯參數。不過,比起所謂的參數編輯,我們更看重可讀性,且後者比較好辦:
+ 把多個參數放在同一行,是為了減少函式呼叫所需的行數,除非影響到可讀性。有人認為把每個參數都獨立成行,不僅更好讀,而且方便編輯參數。不過,比起所謂的參數編輯,我們更看重可讀性,且後者比較好辦:
- 如果一些參數本身就是略複雜的表達式,且降低了可讀性。那麼可以直接創建臨時變數描述該表達式,並傳遞給函數:
+ 如果一些參數本身就是略複雜的表達式,且降低了可讀性。那麼可以直接創建臨時變數描述該表達式,並傳遞給函式:
.. code-block:: c++
@@ -242,9 +242,9 @@
.. tip::
- 你平時怎麼格式化函數呼叫,就怎麼格式化:ref:`braced_initializer_list`。
+ 你平時怎麼格式化函式呼叫,就怎麼格式化:ref:`braced_initializer_list`。
- 如果列表初始化伴隨著名字,比如類型或變數名,你可以當名字是函數、{} 是函數呼叫的括號來格式化它。反之,就當它有個長度為零的名字。
+ 如果列表初始化伴隨著名字,比如類型或變數名,你可以當名字是函式、{} 是函式呼叫的括號來格式化它。反之,就當它有個長度為零的名字。
.. code-block:: c++
@@ -488,7 +488,7 @@
注意, 上例的邏輯與 (``&&``) 操作符均位於行尾. 這格式在 Google 裡很常見,你要把所有操作符放在開頭也可以。可以考慮額外插入圓括號, 合理使用的話對增強可讀性是很有幫助的. 此外直接用符號形式的操作符,比如 ``&&`` 和 ``~``, 不要用詞語形式的 ``and`` 和 ``compl``.
-8.12. 函數返回值
+8.12. 函式返回值
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. tip::
@@ -497,7 +497,7 @@
假如你寫 ``x = epr`` 時本來就會加上括號,那 ``return expr;`` 也可如法炮製。
-函數返回時不要使用圓括號:
+函式返回時不要使用圓括號:
.. code-block:: c++
@@ -511,7 +511,7 @@
.. code-block:: c++
return (value); // 畢竟你從來不會寫 var = (value);
- return(result); // return 可不是函數!
+ return(result); // return 可不是函式!
8.13. 變數及陣列初始化
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -531,7 +531,7 @@
string name = "Some Name";
string name{"Some Name"};
-請務必小心列表初始化 {...} 用 ``std::initializer_list`` 建構子初始化出的類型。非空列表初始化就會優先呼叫 ``std::initializer_list``, 不過空列表初始化除外,後者原則上會呼叫默認建構函數。為了強制禁用 ``std::initializer_list`` 構造函數,請改用括號。
+請務必小心列表初始化 {...} 用 ``std::initializer_list`` 建構子初始化出的類型。非空列表初始化就會優先呼叫 ``std::initializer_list``, 不過空列表初始化除外,後者原則上會呼叫默認建構函式。為了強制禁用 ``std::initializer_list`` 構造函式,請改用括號。
.. code-block:: c++
@@ -709,9 +709,9 @@
// 繼承與初始化列表中的冒號前後恆有空格。
class Foo : public Bar {
public:
- // 至於內聯函數實現,在大括號內部加上空格並編寫實現。
+ // 至於內聯函式實作,在大括號內部加上空格並編寫實作。
Foo(int b) : Bar(), baz_(b) {} // 大括號裡面是空的話,不加空格。
- void Reset() { baz_ = 0; } // 用括號把大括號與實現分開。
+ void Reset() { baz_ = 0; } // 用括號把大括號與實作分開。
...
添加冗余的留白會給其他人編輯時造成額外負擔. 因此, 行尾不要留空格. 如果確定一行程式碼已經修改完畢, 將多餘的空格去掉; 或者在專門清理空格時去掉(確信沒有其他人在處理). (Yang.Y 注: 現在大部分程式碼編輯器稍加設置後, 都支持自動刪除行首/行尾空格, 如果不支持, 考慮換一款編輯器或 IDE)
@@ -777,13 +777,13 @@
垂直留白越少越好.
-這不僅僅是規則而是原則問題了: 不在萬不得已, 不要使用空行. 尤其是: 兩個函數定義之間的空行不要超過 2 行, 函數體首尾不要留空行, 函數體中也不要隨意添加空行.
+這不僅僅是規則而是原則問題了: 不在萬不得已, 不要使用空行. 尤其是: 兩個函式定義之間的空行不要超過 2 行, 函式體首尾不要留空行, 函式體中也不要隨意添加空行.
基本原則是: 同一屏可以顯示的程式碼越多, 越容易理解程式的控制串流. 當然, 過於密集的程式碼塊和過於疏鬆的程式碼塊同樣難看, 取決於你的判斷. 但通常是垂直留白越少越好.
空行心得如下:
-* 函數體內開頭或結尾的空行可讀性微乎其微。
+* 函式體內開頭或結尾的空行可讀性微乎其微。
* 在多重 if-else 塊裡加空行或許有點可讀性。
譯者 (YuleFox) 筆記
@@ -793,23 +793,23 @@
#. 行寬原則上不超過 80 列, 把 22 寸的顯示屏都占完, 怎麼也說不過去;
#. 盡量不使用非 ASCII 字符, 如果使用的話, 參考 UTF-8 格式 (尤其是 UNIX/Linux 下, Windows 下可以考慮寬字符), 盡量不將字符串常數耦合到程式碼中, 比如獨立出資源文件, 這不僅僅是風格問題了;
#. UNIX/Linux 下無條件使用空格, MSVC 的話使用 Tab 也無可厚非;
-#. 函數參數, 邏輯條件, 初始化列表: 要麼所有參數和函數名放在同一行, 要麼所有參數並排分行;
-#. 除函數定義的左大括號可以置於行首外, 包括函數/類/結構體/列舉宣告, 各種語句的左大括號置於行尾, 所有右大括號獨立成行;
+#. 函式參數, 邏輯條件, 初始化列表: 要麼所有參數和函式名放在同一行, 要麼所有參數並排分行;
+#. 除函式定義的左大括號可以置於行首外, 包括函式/類/結構體/列舉宣告, 各種語句的左大括號置於行尾, 所有右大括號獨立成行;
#. ``.``/``->`` 操作符前後不留空格, ``*``/``&`` 不要前後都留, 一個就可, 靠左靠右依各人喜好;
-#. 前處理指令/命名空間不使用額外縮排, 類/結構體/列舉/函數/語句使用縮排;
+#. 前處理指令/命名空間不使用額外縮排, 類/結構體/列舉/函式/語句使用縮排;
#. 初始化用 ``=`` 還是 ``()`` 依個人喜好, 統一就好;
#. ``return`` 不要加 ``()``;
#. 水平/垂直留白不要濫用, 怎麼易讀怎麼來.
-#. 關於 UNIX/Linux 風格為什麼要把左大括號置於行尾 (``.cc`` 文件的函數實現處, 左大括號位於行首), 我的理解是程式碼看上去比較簡約, 想想行首除了函數體被一對大括號封在一起之外, 只有右大括號的程式碼看上去確實也舒服; Windows 風格將左大括號置於行首的優點是匹配情況一目瞭然.
+#. 關於 UNIX/Linux 風格為什麼要把左大括號置於行尾 (``.cc`` 文件的函式實作處, 左大括號位於行首), 我的理解是程式碼看上去比較簡約, 想想行首除了函式體被一對大括號封在一起之外, 只有右大括號的程式碼看上去確實也舒服; Windows 風格將左大括號置於行首的優點是匹配情況一目瞭然.
譯者(acgtyrant)筆記
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-#. 80 行限制事實上有助於避免程式碼可讀性失控,比如超多重嵌套塊,超多重函數呼叫等等。
+#. 80 行限制事實上有助於避免程式碼可讀性失控,比如超多重嵌套塊,超多重函式呼叫等等。
#. Linux 上設置好了 Locale 就幾乎一勞永逸設置好所有開發環境的編碼,不像奇葩的 Windows.
#. Google 強調有一對 if-else 時,不論有沒有嵌套,都要有大括號。Apple 正好`有栽過跟頭 `_.
#. 其實我主張指標/地址操作符與變數名緊鄰,``int* a, b`` vs ``int *a, b``, 新手會誤以為前者的 ``b`` 是 ``int *`` 變量,但後者就不一樣了,高下立判。
#. 在這風格指南裡我才剛知道 C++ 原來還有所謂的 `Alternative operator representations `_, 大概沒人用吧。
#. 注意建構子初始值列表(Constructer Initializer List)與列表初始化(Initializer List)是兩碼事,我就差點混淆了它們的翻譯。
#. 事實上,如果你熟悉英語本身的書寫規則,就會發現該風格指南在格式上的規定與英語語法相當一脈相承。比如普通標點符號和單詞後面還有文本的話,總會留一個空格;特殊符號與單詞之間就不用留了,比如 ``if (true)`` 中的圓括號與 ``true``.
-#. 本風格指南沒有明確規定 void 函數里要不要用 return 語句,不過就 Google 開源專案 leveldb 並沒有寫;此外從 `Is a blank return statement at the end of a function whos return type is void necessary? `_ 來看,``return;`` 比 ``return ;`` 更約定俗成(事實上 cpplint 會對後者報錯,指出分號前有多餘的空格),且可用來提前跳出函數棧。
+#. 本風格指南沒有明確規定 void 函式里要不要用 return 語句,不過就 Google 開源專案 leveldb 並沒有寫;此外從 `Is a blank return statement at the end of a function whos return type is void necessary? `_ 來看,``return;`` 比 ``return ;`` 更約定俗成(事實上 cpplint 會對後者報錯,指出分號前有多餘的空格),且可用來提前跳出函式棧。
diff --git a/google-cpp-styleguide/headers.rst b/google-cpp-styleguide/headers.rst
index 1964be6d..c3980018 100644
--- a/google-cpp-styleguide/headers.rst
+++ b/google-cpp-styleguide/headers.rst
@@ -1,7 +1,7 @@
1. 標頭檔
----------------
-通常每一個 ``.cc`` 文件都有一個對應的 ``.h`` 文件。也有一些常見例外, 如單元測試程式碼和只引入 ``main()`` 函數的 ``.cc`` 文件。
+通常每一個 ``.cc`` 文件都有一個對應的 ``.h`` 文件。也有一些常見例外, 如單元測試程式碼和只引入 ``main()`` 函式的 ``.cc`` 文件。
正確使用標頭檔可令程式碼在可讀性、文件大小和編譯性能上大為改觀。
@@ -20,9 +20,9 @@
只有少數的例外,一個標頭檔不是自我滿足的而是用來安插到程式碼某處裡。例如某些文件會被重複的 include 或是文件內容實際上是特定平台(platform-specific)擴展部分。這些文件就要用 ``.inc`` 文件擴展名。
-如果 ``.h`` 文件宣告了一個樣板或內聯 (inline) 函數,同時也在該文件加以定義。凡是有用到這些的 ``.cc`` 文件,就得統統引入該標頭檔,否則程式可能會在構建中連結失敗。現在不要把這些定義放到分離的 ``-inl.h`` 文件裡了(譯者註:過去該規範曾提倡把定義放到 -inl.h 裡過)。
+如果 ``.h`` 文件宣告了一個樣板或內聯 (inline) 函式,同時也在該文件加以定義。凡是有用到這些的 ``.cc`` 文件,就得統統引入該標頭檔,否則程式可能會在構建中連結失敗。現在不要把這些定義放到分離的 ``-inl.h`` 文件裡了(譯者註:過去該規範曾提倡把定義放到 -inl.h 裡過)。
-有個例外:如果某函數樣板為所有相關模板參數顯式實例化,或本身就是類別的一個私有成員,那麼它就只能定義在實例化該模板的 ``.cc`` 文件裡。
+有個例外:如果某函式樣板為所有相關模板參數顯式實例化,或本身就是類別的一個私有成員,那麼它就只能定義在實例化該模板的 ``.cc`` 文件裡。
.. _define-guard:
@@ -52,7 +52,7 @@
避免使用前置宣告,直接引入需要的標頭檔即可。
定義:
- 前置宣告是不提供與之關連的定義下,宣告一個類別、函數或是樣板。
+ 前置宣告是不提供與之關連的定義下,宣告一個類別、函式或是樣板。
優點:
@@ -71,7 +71,7 @@
結論:
* 在任何狀況下避免使用前置宣告。
- * 當在標頭檔內使用到函數宣告時,總是引入對應的標頭檔。
+ * 當在標頭檔內使用到函式宣告時,總是引入對應的標頭檔。
* 當使用類別樣板時,建議引入對應得標頭檔。
@@ -79,32 +79,32 @@
.. _inline-functions:
-1.4. 內聯函數 (Inline Functions)
+1.4. 內聯函式 (Inline Functions)
~~~~~~~~~~~~~~~~~~~~~~
.. tip::
- 只有當函數非常的短,例如只有 10 行甚至更少的時候,才將其定義為內聯函數。
+ 只有當函式非常的短,例如只有 10 行甚至更少的時候,才將其定義為內聯函式。
定義:
- 當函數被宣告為內聯函數之後,代表你允許編譯器將其展開在該函數被呼叫的位置,而不是原來的函數呼叫機制進行。
+ 當函式被宣告為內聯函式之後,代表你允許編譯器將其展開在該函式被呼叫的位置,而不是原來的函式呼叫機制進行。
優點:
- 當函數主體比較小的時候,內聯該函數可以產生更有效率目標程式碼 (object code)。對於存取函數 (accessors)、賦值函數 (mutators) 以及其它函數體比較短或性能關鍵的函數,可以依據需求將其轉為內聯函數。
+ 當函式主體比較小的時候,內聯該函式可以產生更有效率目標程式碼 (object code)。對於存取函式 (accessors)、賦值函式 (mutators) 以及其它函式體比較短或性能關鍵的函式,可以依據需求將其轉為內聯函式。
缺點:
- 濫用內聯反而會導致程式變慢。內聯可能使目標程式碼變大或變小,這取決於內聯函數主體的大小。一個非常短小的存取函數被內聯通常會減少目標程式碼的大小, 但內聯一個相當大的函數將戲劇性的增加目標程式碼大小。現代的處理器 (CPU) 具備有指令緩存 (instruction cache),執行小巧的程式碼往往執行更快。
+ 濫用內聯反而會導致程式變慢。內聯可能使目標程式碼變大或變小,這取決於內聯函式主體的大小。一個非常短小的存取函式被內聯通常會減少目標程式碼的大小, 但內聯一個相當大的函式將戲劇性的增加目標程式碼大小。現代的處理器 (CPU) 具備有指令緩存 (instruction cache),執行小巧的程式碼往往執行更快。
結論:
- 一個較為合理的經驗準則是,不要內聯超過 10 行的函數。謹慎對待解構子, 解構子往往比其表面看起來要更長, 因為有隱含的成員和父類別解構子被呼叫!
+ 一個較為合理的經驗準則是,不要內聯超過 10 行的函式。謹慎對待解構子, 解構子往往比其表面看起來要更長, 因為有隱含的成員和父類別解構子被呼叫!
- 另一個實用的經驗準則: 內聯那些包含循環或 ``switch`` 語句的函數常常是得不償失的 (除非在大多數情況下, 這些循環或 ``switch`` 語句從不被執行)。
+ 另一個實用的經驗準則: 內聯那些包含循環或 ``switch`` 語句的函式常常是得不償失的 (除非在大多數情況下, 這些循環或 ``switch`` 語句從不被執行)。
- 要注意的是,既使函數即使宣告為內聯,也不一定會被編譯器內聯。例如虛函數 (virtual) 和遞迴函數 (recursive) 就不會被正常內聯。通常, 遞迴函數不應該宣告成內聯函數。(譯註: 遞迴呼叫堆棧的展開並不像循環那麼簡單,例如遞迴層數在編譯時可能是未知的,大多數編譯器都不支持內聯遞迴函數)。虛函數內聯的主要原因則是想把它的函數主體放在類別的定義內, 可能式為了方便,或是當作文件描述其行為。例如存取函數或賦值函數。
+ 要注意的是,既使函式即使宣告為內聯,也不一定會被編譯器內聯。例如虛函式 (virtual) 和遞迴函式 (recursive) 就不會被正常內聯。通常, 遞迴函式不應該宣告成內聯函式。(譯註: 遞迴呼叫堆棧的展開並不像循環那麼簡單,例如遞迴層數在編譯時可能是未知的,大多數編譯器都不支持內聯遞迴函式)。虛函式內聯的主要原因則是想把它的函式主體放在類別的定義內, 可能式為了方便,或是當作文件描述其行為。例如存取函式或賦值函式。
.. _name-and-order-of-includes
@@ -120,7 +120,7 @@
#include "base/logging.h"
-另一個例子是,若 ``dir/foo.cc`` 或 ``dir/foo_test.cc`` 的主要作用是實現或測試 ``dir2/foo2.h`` 的功能,``foo.cc`` 中引入標頭檔的次序應如下:
+另一個例子是,若 ``dir/foo.cc`` 或 ``dir/foo_test.cc`` 的主要作用是實作或測試 ``dir2/foo2.h`` 的功能,``foo.cc`` 中引入標頭檔的次序應如下:
#. ``dir2/foo2.h``
#. C 系統文件
diff --git a/google-cpp-styleguide/magic.rst b/google-cpp-styleguide/magic.rst
index f2191072..9f6c8b92 100644
--- a/google-cpp-styleguide/magic.rst
+++ b/google-cpp-styleguide/magic.rst
@@ -1,7 +1,7 @@
4. 來自 Google 的奇技
--------------------------------------
-Google 用了很多自己實現的技巧 / 工具使 C++ 程式碼更加健壯, 我們使用 C++ 的方式可能和你在其它地方見到的有所不同.
+Google 用了很多自己實作的技巧 / 工具使 C++ 程式碼更加健壯, 我們使用 C++ 的方式可能和你在其它地方見到的有所不同.
4.1. 所有權與智慧指標
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -12,7 +12,7 @@ Google 用了很多自己實現的技巧 / 工具使 C++ 程式碼更加健壯,
定義:
- 所有權是一種登記/管理動態內存和其它資源的技術。動態分配出的對象的所有主是一個對象或函數,後者負責確保當前者無用時就自動銷毀前者。所有權有時可以共享,那麼就由最後一個所有主來負責銷毀它。甚至也可以不用共享,在程式碼中直接把所有權傳遞給其它對象。
+ 所有權是一種登記/管理動態內存和其它資源的技術。動態分配出的對象的所有主是一個對象或函式,後者負責確保當前者無用時就自動銷毀前者。所有權有時可以共享,那麼就由最後一個所有主來負責銷毀它。甚至也可以不用共享,在程式碼中直接把所有權傳遞給其它對象。
其實你可以把智慧指標當成一個重載了 ``*`` 和 ``->`` 的「對象」來看。智能指針類型被用來自動化所有權的登記工作,來確保執行銷毀義務到位。`std::unique_ptr `_ 是 C++11 新推出的一種智能指針類型,用來表示動態分配出的對象的「獨一無二」所有權;當 ``std::unique_ptr`` 離開作用域,對象就會被銷毀。不能複製 ``std::unique_ptr``, 但可以把它移動(move)給新所有主。`std::shared_ptr `_ 同樣表示動態分配對象的所有權,但可以被共享,也可以被複製;對象的所有權由所有複製者共同擁有,最後一個複製者被銷毀時,對象也會隨著被銷毀。
diff --git a/google-cpp-styleguide/naming.rst b/google-cpp-styleguide/naming.rst
index c6ca3efd..201f1987 100644
--- a/google-cpp-styleguide/naming.rst
+++ b/google-cpp-styleguide/naming.rst
@@ -1,7 +1,7 @@
6. 命名約定
------------------
-最重要的一致性規則是命名管理. 命名風格快速獲知名字代表是什麼東東: 類型? 變數? 函數? 常數? 巨集 ... ? 甚至不需要去查找類型宣告. 我們大腦中的模式匹配引擎可以非常可靠的處理這些命名規則.
+最重要的一致性規則是命名管理. 命名風格快速獲知名字代表是什麼東東: 類型? 變數? 函式? 常數? 巨集 ... ? 甚至不需要去查找類型宣告. 我們大腦中的模式匹配引擎可以非常可靠的處理這些命名規則.
命名規則具有一定隨意性, 但相比按個人喜好命名, 一致性更重, 所以不管你怎麼想, 規則總歸是規則.
@@ -10,7 +10,7 @@
.. tip::
- 函數命名,變數命名,文件命名要有描述性;少用縮寫。
+ 函式命名,變數命名,文件命名要有描述性;少用縮寫。
盡可能給有描述性的命名,別心疼空間,畢竟讓程式碼易於新讀者理解很重要。不要用只有專案開發者能理解的縮寫,也不要通過砍掉幾個字母來縮寫單詞。
@@ -51,7 +51,7 @@
通常應盡量讓文件名更加明確. ``http_server_logs.h`` 就比 ``logs.h`` 要好. 定義類時文件名一般成對出現, 如 ``foo_bar.h`` 和 ``foo_bar.cc``, 對應於類 ``FooBar``.
- 內聯函數必須放在 ``.h`` 文件中. 如果內聯函數比較短, 就直接放在 ``.h`` 中.
+ 內聯函式必須放在 ``.h`` 文件中. 如果內聯函式比較短, 就直接放在 ``.h`` 中.
6.3. 類型命名
~~~~~~~~~~~~~~~~~~~~~~
@@ -144,18 +144,18 @@
.. _function-names:
-6.6. 函數命名
+6.6. 函式命名
~~~~~~~~~~~~~~~~~~~~~~
.. tip::
- 常規函數使用大小寫混合, 取值和設值函數則要求與變數名匹配: ``MyExcitingFunction()``, ``MyExcitingMethod()``, ``my_exciting_member_variable()``, ``set_my_exciting_member_variable()``.
+ 常規函式使用大小寫混合, 取值和設值函式則要求與變數名匹配: ``MyExcitingFunction()``, ``MyExcitingMethod()``, ``my_exciting_member_variable()``, ``set_my_exciting_member_variable()``.
-常規函數:
+常規函式:
- 函數名的每個單詞首字母大寫, 沒有底線。
+ 函式名的每個單詞首字母大寫, 沒有底線。
- 如果你的某函數出錯時就要直接 crash, 那麼就在函數名加上 OrDie. 但這函數本身必須集成在產品程式碼裡,且平時也可能會出錯。
+ 如果你的某函式出錯時就要直接 crash, 那麼就在函式名加上 OrDie. 但這函式本身必須集成在產品程式碼裡,且平時也可能會出錯。
.. code-block:: c++
@@ -163,9 +163,9 @@
DeleteUrl()
OpenFileOrDie()
-取值和設值函數:
+取值和設值函式:
- 取值(Accessors)和設值(Mutators)函數要與存取的變數名匹配. 這兒摘錄一個類, ``num_entries_`` 是該類的實例變量:
+ 取值(Accessors)和設值(Mutators)函式要與存取的變數名匹配. 這兒摘錄一個類, ``num_entries_`` 是該類的實例變量:
.. code-block:: c++
@@ -179,7 +179,7 @@
int num_entries_;
};
- 其它非常短小的內聯函數名也可以用小寫字母, 例如. 如果你在循環中呼叫這樣的函數甚至都不用緩存其返回值, 小寫命名就可以接受.
+ 其它非常短小的內聯函式名也可以用小寫字母, 例如. 如果你在循環中呼叫這樣的函式甚至都不用緩存其返回值, 小寫命名就可以接受.
6.7. 命名空間命名
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -236,7 +236,7 @@
``bigopen()``:
- 函數名, 參照 ``open()`` 的形式
+ 函式名, 參照 ``open()`` 的形式
``uint``:
diff --git a/google-cpp-styleguide/others.rst b/google-cpp-styleguide/others.rst
index 468706bc..69c525b1 100644
--- a/google-cpp-styleguide/others.rst
+++ b/google-cpp-styleguide/others.rst
@@ -10,7 +10,7 @@
定義:
- 在 C 語言中, 如果函數需要修改變數的值, 參數必須為指標, 如 ``int foo(int *pval)``. 在 C++ 中, 函數還可以宣告引用參數: ``int foo(int &val)``.
+ 在 C 語言中, 如果函式需要修改變數的值, 參數必須為指標, 如 ``int foo(int *pval)``. 在 C++ 中, 函式還可以宣告引用參數: ``int foo(int &val)``.
優點:
@@ -22,7 +22,7 @@
結論:
- 函數參數列表中, 所有引用參數都必須是 ``const``:
+ 函式參數列表中, 所有引用參數都必須是 ``const``:
.. code-block:: c++
@@ -33,51 +33,51 @@
有時候,在輸入形參中用 ``const T*`` 指標比 ``const T&`` 更明智。比如:
* 你會傳 null 指標。
- * 函數要把指標或對地址的引用賦值給輸入形參。
+ * 函式要把指標或對地址的引用賦值給輸入形參。
總之大多時候輸入形參往往是 ``const T&``. 若用 ``const T*`` 說明輸入另有處理。所以若你要用 ``const T*``, 則應有理有據,否則會害得讀者誤解。
-5.2. 右值引用
+5.2. 右值參考
~~~~~~~~~~~~~~~~~~~~~~
.. tip::
- 只在定義移動建構子與移動賦值操作時使用右值引用. 不要使用 ``std::forward``.
+ 只在定義移動建構子與移動賦值操作時使用右值參考. 不要使用 ``std::forward``.
定義:
- 右值引用是一種只能綁定到臨時對象的引用的一種, 其語法與傳統的引用語法相似. 例如, ``void f(string&& s)``; 宣告了一個其參數是一個字符串的右值引用的函數.
+ 右值參考是一種只能綁定到臨時對象的引用的一種, 其語法與傳統的引用語法相似. 例如, ``void f(string&& s)``; 宣告了一個其參數是一個字符串的右值參考的函式.
優點:
- 用於定義移動建構子 (使用類的右值引用進行建構的函數) 使得移動一個值而非拷貝之成為可能. 例如, 如果 ``v1`` 是一個 ``vector``, 則 ``auto v2(std::move(v1))`` 將很可能不再進行大量的數據複製而只是簡單地進行指標操作, 在某些情況下這將帶來大幅度的性能提升.
+ 用於定義移動建構子 (使用類的右值參考進行建構的函式) 使得移動一個值而非拷貝之成為可能. 例如, 如果 ``v1`` 是一個 ``vector``, 則 ``auto v2(std::move(v1))`` 將很可能不再進行大量的數據複製而只是簡單地進行指標操作, 在某些情況下這將帶來大幅度的性能提升.
- 右值引用使得編寫通用的函數封裝來轉發其參數到另外一個函數成為可能, 無論其參數是否是臨時對象都能正常工作.
+ 右值參考使得編寫通用的函式封裝來轉發其參數到另外一個函式成為可能, 無論其參數是否是臨時對象都能正常工作.
- 右值引用能實現可移動但不可拷貝的類型, 這一特性對那些在拷貝方面沒有實際需求, 但有時又需要將它們作為函數參數傳遞或塞入容器的類型很有用.
+ 右值參考能實作可移動但不可拷貝的類型, 這一特性對那些在拷貝方面沒有實際需求, 但有時又需要將它們作為函式參數傳遞或塞入容器的類型很有用.
要高效率地使用某些標準函式庫類型, 例如 ``std::unique_ptr``, ``std::move`` 是必需的.
缺點:
- 右值引用是一個相對比較新的特性 (由 C++11 引入), 它尚未被廣泛理解. 類似引用崩潰, 移動建構子的自動推導這樣的規則都是很複雜的.
+ 右值參考是一個相對比較新的特性 (由 C++11 引入), 它尚未被廣泛理解. 類似引用崩潰, 移動建構子的自動推導這樣的規則都是很複雜的.
結論:
- 只在定義移動建構子與移動賦值操作時使用右值引用, 不要使用 ``std::forward`` 功能函數. 你可能會使用 ``std::move`` 來表示將值從一個對象移動而不是複製到另一個對像.
+ 只在定義移動建構子與移動賦值操作時使用右值參考, 不要使用 ``std::forward`` 功能函式. 你可能會使用 ``std::move`` 來表示將值從一個對象移動而不是複製到另一個對像.
.. _function-overloading:
-5.3. 函數重載
+5.3. 函式重載
~~~~~~~~~~~~~~~~~~~~~~
.. tip::
- 若要用好函數重載,最好能讓讀者一看呼叫點(call site)就胸有成竹,不用花心思猜測呼叫的重載函數到底是哪一種。該規則適用於建構子。
+ 若要用好函式重載,最好能讓讀者一看呼叫點(call site)就胸有成竹,不用花心思猜測呼叫的重載函式到底是哪一種。該規則適用於建構子。
定義:
- 你可以編寫一個參數類型為 ``const string&`` 的函數, 然後用另一個參數類型為 ``const char*`` 的函數重載它:
+ 你可以編寫一個參數類型為 ``const string&`` 的函式, 然後用另一個參數類型為 ``const char*`` 的函式重載它:
.. code-block:: c++
@@ -89,36 +89,36 @@
優點:
- 通過重載參數不同的同名函數, 令程式碼更加直觀. 樣板化程式碼需要重載, 同時為使用者帶來便利.
+ 通過重載參數不同的同名函式, 令程式碼更加直觀. 樣板化程式碼需要重載, 同時為使用者帶來便利.
缺點:
- 如果函數單單靠不同的參數類型而重載(acgtyrant 註:這意味著參數數量不變),讀者就得十分熟悉 C++ 五花八門的匹配規則,以瞭解匹配過程具體到底如何。另外,當派生類只重載了某個函數的部分變體,繼承語義容易令人困惑。
+ 如果函式單單靠不同的參數類型而重載(acgtyrant 註:這意味著參數數量不變),讀者就得十分熟悉 C++ 五花八門的匹配規則,以瞭解匹配過程具體到底如何。另外,當派生類只重載了某個函式的部分變體,繼承語義容易令人困惑。
結論:
- 如果你打算重載一個函數, 可以試試改在函數名裡加上參數信息。例如,用 ``AppendString()`` 和 ``AppendInt()`` 等, 而不是一口氣重載多個 ``Append()``.
+ 如果你打算重載一個函式, 可以試試改在函式名裡加上參數信息。例如,用 ``AppendString()`` 和 ``AppendInt()`` 等, 而不是一口氣重載多個 ``Append()``.
5.4. 預設參數
~~~~~~~~~~~~~~~~~~~~~~
.. tip::
- 我們不允許使用缺省函數參數,少數極端情況除外。盡可能改用函數重載。
+ 我們不允許使用缺省函式參數,少數極端情況除外。盡可能改用函式重載。
優點:
- 當你有相依性預設參數的函數時,你也許偶爾會修改修改這些缺省參數。通過缺省參數,不用再為個別情況而特意定義一大堆函數了。與函數重載相比,缺省參數語法更為清晰,程式碼少,也很好地區分了「必選參數」和「可選參數」。
+ 當你有相依性預設參數的函式時,你也許偶爾會修改修改這些缺省參數。通過缺省參數,不用再為個別情況而特意定義一大堆函式了。與函式重載相比,缺省參數語法更為清晰,程式碼少,也很好地區分了「必選參數」和「可選參數」。
缺點:
- 預設參數會干擾函數指標,害得後者的函數簽名(function signature)往往對不上所實際要呼叫的函數簽名。即在一個現有函數添加缺省參數,就會改變它的類型,那麼呼叫其地址的程式碼可能會出錯,不過函數重載就沒這問題了。此外,缺省參數會造成臃腫的程式碼,畢竟它們在每一個呼叫點(call site)都有重複(acgtyrant 註:我猜可能是因為呼叫函數的程式碼表面上看來省去了不少參數,但編譯器在編譯時還是會在每一個呼叫程式碼裡統統補上所有默認實參信息,造成大量的重複)。函數重載正好相反,畢竟它們所謂的「缺省參數」只會出現在函數定義裡。
+ 預設參數會干擾函式指標,害得後者的函式簽名(function signature)往往對不上所實際要呼叫的函式簽名。即在一個現有函式添加缺省參數,就會改變它的類型,那麼呼叫其地址的程式碼可能會出錯,不過函式重載就沒這問題了。此外,缺省參數會造成臃腫的程式碼,畢竟它們在每一個呼叫點(call site)都有重複(acgtyrant 註:我猜可能是因為呼叫函式的程式碼表面上看來省去了不少參數,但編譯器在編譯時還是會在每一個呼叫程式碼裡統統補上所有默認實參信息,造成大量的重複)。函式重載正好相反,畢竟它們所謂的「缺省參數」只會出現在函式定義裡。
結論:
- 由於缺點並不是很嚴重,有些人依舊偏愛預設參數勝於函數重載。所以除了以下情況,我們要求必須顯式提供所有參數(acgtyrant 註:即不能再通過缺省參數來省略參數了)。
+ 由於缺點並不是很嚴重,有些人依舊偏愛預設參數勝於函式重載。所以除了以下情況,我們要求必須顯式提供所有參數(acgtyrant 註:即不能再通過缺省參數來省略參數了)。
- 其一,位於 ``.cc`` 文件裡的靜態函數或匿名空間函數,畢竟都只能在局部文件裡呼叫該函數了。
+ 其一,位於 ``.cc`` 文件裡的靜態函式或匿名空間函式,畢竟都只能在局部文件裡呼叫該函式了。
其二,可以在建構子里用預設參數,畢竟不可能取得它們的地址。
@@ -156,7 +156,7 @@
.. tip::
- 我們允許合理的使用友元類及友元函數.
+ 我們允許合理的使用友元類及友元函式.
通常友元應該定義在同一文件內, 避免程式碼讀者跑到其它文件查找使用該私有成員的類. 經常用到友元的一個地方是將 ``FooBuilder`` 宣告為 ``Foo`` 的友元, 以便 ``FooBuilder`` 正確建構 ``Foo`` 的內部狀態, 而無需將該狀態暴露出來. 某些情況下, 將一個單元測試類宣告成待測類的友元會很方便.
@@ -171,21 +171,21 @@
優點:
- - 例外允許應用高層決定如何處理在底層嵌套函數中「不可能發生」的失敗(failures),不用管那些含糊且容易出錯的錯誤程式碼(acgtyrant 註:error code, 我猜是C語言函數返回的非零 int 值)。
+ - 例外允許應用高層決定如何處理在底層嵌套函式中「不可能發生」的失敗(failures),不用管那些含糊且容易出錯的錯誤程式碼(acgtyrant 註:error code, 我猜是C語言函式返回的非零 int 值)。
- 很多現代語言都用例外。引入異常使得 C++ 與 Python, Java 以及其它類 C++ 的語言更一脈相承。
- 有些第三方 C++ 庫相依性例外,禁用異常就不好用了。
- - 例外是處理建構子失敗的唯一途徑。雖然可以用工廠函數(acgtyrant 註:factory function, 出自 C++ 的一種設計模式,即「簡單工廠模式」)或 ``Init()`` 方法代替異常, but these require heap allocation or a new "invalid" state, respectively.
+ - 例外是處理建構子失敗的唯一途徑。雖然可以用工廠函式(acgtyrant 註:factory function, 出自 C++ 的一種設計模式,即「簡單工廠模式」)或 ``Init()`` 方法代替異常, but these require heap allocation or a new "invalid" state, respectively.
- 在測試框架裡很好用。
缺點:
- - 在現有函數中添加 ``throw`` 語句時,你必須檢查所有呼叫點。要麼讓所有呼叫點統統具備最低限度的例外安全保證,要麼眼睜睜地看異常一路歡快地往上跑,最終中斷掉整個程式。舉例,``f()`` 呼叫 ``g()``, ``g()`` 又呼叫 ``h()``, 且 ``h`` 丟出的異常被 ``f`` 捕獲。當心 ``g``, 否則會沒妥善清理好。
+ - 在現有函式中添加 ``throw`` 語句時,你必須檢查所有呼叫點。要麼讓所有呼叫點統統具備最低限度的例外安全保證,要麼眼睜睜地看異常一路歡快地往上跑,最終中斷掉整個程式。舉例,``f()`` 呼叫 ``g()``, ``g()`` 又呼叫 ``h()``, 且 ``h`` 丟出的異常被 ``f`` 捕獲。當心 ``g``, 否則會沒妥善清理好。
- - 還有更常見的,例外會徹底擾亂程式的執行串流程並難以判斷,函數也許會在你意料不到的地方返回。你或許會加一大堆何時何處處理異常的規定來降低風險,然而開發者的記憶負擔更重了。
+ - 還有更常見的,例外會徹底擾亂程式的執行串流程並難以判斷,函式也許會在你意料不到的地方返回。你或許會加一大堆何時何處處理異常的規定來降低風險,然而開發者的記憶負擔更重了。
- 例外安全需要RAII和不同的編碼實踐. 要輕鬆編寫出正確的異常安全程式碼需要大量的支持機制. 更進一步地說, 為了避免讀者理解整個呼叫表, 異常安全必須隔絕從持續狀態寫到 "提交" 狀態的邏輯. 這一點有利有弊 (因為你也許不得不為了隔離提交而混淆程式碼). 如果允許使用異常, 我們就不得不時刻關注這樣的弊端, 即使有時它們並不值得.
@@ -247,7 +247,7 @@
RTTI 有合理的用途但是容易被濫用, 因此在使用時請務必注意. 在單元測試中可以使用 RTTI, 但是在其他程式碼中請盡量避免. 尤其是在新程式碼中, 使用 RTTI 前務必三思. 如果你的程式碼需要根據不同的對象類型執行不同的行為的話, 請考慮用以下的兩種替代方案之一查詢類型:
- 虛函數可以根據子類類型的不同而執行不同程式碼. 這是把工作交給了對象本身去處理.
+ 虛函式可以根據子類類型的不同而執行不同程式碼. 這是把工作交給了對象本身去處理.
如果這一工作需要在對象之外完成, 可以考慮使用雙重分發的方案, 例如使用訪問者設計模式. 這就能夠在對像之外進行類型判斷.
@@ -266,7 +266,7 @@
一旦在類層級中加入新的子類, 像這樣的程式碼往往會崩潰. 而且, 一旦某個子類的屬性改變了, 你很難找到並修改所有受影響的程式碼塊.
- 不要去手工實現一個類似 RTTI 的方案. 反對 RTTI 的理由同樣適用於這些方案, 比如帶類型標籤的類繼承體系. 而且, 這些方案會掩蓋你的真實意圖.
+ 不要去手工實作一個類似 RTTI 的方案. 反對 RTTI 的理由同樣適用於這些方案, 比如帶類型標籤的類繼承體系. 而且, 這些方案會掩蓋你的真實意圖.
5.9. 類型轉換
~~~~~~~~~~~~~~~~~~~~~~
@@ -314,7 +314,7 @@
缺點:
- 串流使得 ``pread()`` 等功能函數很難執行. 如果不使用 ``printf`` 風格的格式化字符串, 某些格式化操作 (尤其是常用的格式字符串 ``%.*s``) 用流處理性能是很低的. 流不支持字符串操作符重新排序 (%1s), 而這一點對於軟件國際化很有用.
+ 串流使得 ``pread()`` 等功能函式很難執行. 如果不使用 ``printf`` 風格的格式化字符串, 某些格式化操作 (尤其是常用的格式字符串 ``%.*s``) 用流處理性能是很低的. 流不支持字符串操作符重新排序 (%1s), 而這一點對於軟件國際化很有用.
結論:
@@ -335,7 +335,7 @@
由於 ``<<`` 被重載, 編譯器不會報錯. 就因為這一點我們反對使用操作符重載.
- 有人說 ``printf`` 的格式化醜陋不堪, 易讀性差, 但串流也好不到哪兒去. 看看下面兩段程式碼吧, 實現相同的功能, 哪個更清晰?
+ 有人說 ``printf`` 的格式化醜陋不堪, 易讀性差, 但串流也好不到哪兒去. 看看下面兩段程式碼吧, 實作相同的功能, 哪個更清晰?
.. code-block:: c++
@@ -363,7 +363,7 @@
優點:
- 不考慮返回值的話, 前置自增 (``++i``) 通常要比後置自增 (``i++``) 效率更高. 因為後置自增 (或自減) 需要對表達式的值 ``i`` 進行一次拷貝. 如果 ``i`` 是迭代器或其他非數值類型, 拷貝的代價是比較大的. 既然兩種自增方式實現的功能一樣, 為什麼不總是使用前置自增呢?
+ 不考慮返回值的話, 前置自增 (``++i``) 通常要比後置自增 (``i++``) 效率更高. 因為後置自增 (或自減) 需要對表達式的值 ``i`` 進行一次拷貝. 如果 ``i`` 是迭代器或其他非數值類型, 拷貝的代價是比較大的. 既然兩種自增方式實作的功能一樣, 為什麼不總是使用前置自增呢?
缺點:
@@ -382,22 +382,22 @@
定義:
- 在宣告的變數或參數前加上關鍵字 ``const`` 用於指明變量值不可被篡改 (如 ``const int foo`` ). 為類中的函數加上 ``const`` 限定符表明該函數不會修改類成員變量的狀態 (如 ``class Foo { int Bar(char c) const; };``).
+ 在宣告的變數或參數前加上關鍵字 ``const`` 用於指明變量值不可被篡改 (如 ``const int foo`` ). 為類中的函式加上 ``const`` 限定符表明該函式不會修改類成員變量的狀態 (如 ``class Foo { int Bar(char c) const; };``).
優點:
- 大家更容易理解如何使用變數. 編譯器可以更好地進行類型檢測, 相應地, 也能生成更好的程式碼. 人們對編寫正確的程式碼更加自信, 因為他們知道所呼叫的函數被限定了能或不能修改變量值. 即使是在無鎖的多線程程式撰寫中, 人們也知道什麼樣的函數是安全的.
+ 大家更容易理解如何使用變數. 編譯器可以更好地進行類型檢測, 相應地, 也能生成更好的程式碼. 人們對編寫正確的程式碼更加自信, 因為他們知道所呼叫的函式被限定了能或不能修改變量值. 即使是在無鎖的多線程程式撰寫中, 人們也知道什麼樣的函式是安全的.
缺點:
- ``const`` 是入侵性的: 如果你向一個函數傳入 ``const`` 變數, 函數原型宣告中也必須對應 ``const`` 參數 (否則變量需要 ``const_cast`` 類型轉換), 在呼叫庫函數時顯得尤其麻煩.
+ ``const`` 是入侵性的: 如果你向一個函式傳入 ``const`` 變數, 函式原型宣告中也必須對應 ``const`` 參數 (否則變量需要 ``const_cast`` 類型轉換), 在呼叫庫函式時顯得尤其麻煩.
結論:
- ``const`` 變數, 數據成員, 函數和參數為編譯時類型檢測增加了一層保障; 便於盡早發現錯誤. 因此, 我們強烈建議在任何可能的情況下使用 ``const``:
+ ``const`` 變數, 數據成員, 函式和參數為編譯時類型檢測增加了一層保障; 便於盡早發現錯誤. 因此, 我們強烈建議在任何可能的情況下使用 ``const``:
- - 如果函數不會修改傳你入的引用或指標類型參數, 該參數應宣告為 ``const``.
- - 盡可能將函數宣告為 ``const``. 訪問函數應該總是 ``const``. 其他不會修改任何數據成員, 未呼叫非 ``const`` 函數, 不會返回數據成員非 ``const`` 指標或引用的函數也應該宣告成 ``const``.
+ - 如果函式不會修改傳你入的引用或指標類型參數, 該參數應宣告為 ``const``.
+ - 盡可能將函式宣告為 ``const``. 訪問函式應該總是 ``const``. 其他不會修改任何數據成員, 未呼叫非 ``const`` 函式, 不會返回數據成員非 ``const`` 指標或引用的函式也應該宣告成 ``const``.
- 如果數據成員在對象建構之後不再發生變化, 可將其定義為 ``const``.
然而, 也不要發了瘋似的使用 ``const``. 像 ``const int * const * const x;`` 就有些過了, 雖然它非常精確的描述了常數 ``x``. 關注真正有幫助意義的信息: 前面的例子寫成 ``const int** x`` 就夠了.
@@ -415,15 +415,15 @@
.. tip::
- 在 C++11 裡,用 constexpr 來定義真正的常數,或實現常量初始化。
+ 在 C++11 裡,用 constexpr 來定義真正的常數,或實作常量初始化。
定義:
- 變數可以被宣告成 constexpr 以表示它是真正意義上的常數,即在編譯時和運行時都不變。函數或建構子也可以被宣告成 constexpr, 以用來定義 constexpr 變量。
+ 變數可以被宣告成 constexpr 以表示它是真正意義上的常數,即在編譯時和運行時都不變。函式或建構子也可以被宣告成 constexpr, 以用來定義 constexpr 變量。
優點:
- 如今 constexpr 就可以定義浮點式的真・常數,不用再相依性字面值了;也可以定義使用者自定義類型上的常量;甚至也可以定義函數呼叫所返回的常量。
+ 如今 constexpr 就可以定義浮點式的真・常數,不用再相依性字面值了;也可以定義使用者自定義類型上的常量;甚至也可以定義函式呼叫所返回的常量。
缺點:
@@ -431,7 +431,7 @@
結論:
- 靠 constexpr 特性,方才實現了 C++ 在介面上打造真正常數機制的可能。好好用 constexpr 來定義真・常量以及支持常量的函數。Avoid complexifying function definitions to enable their use with constexpr. 千萬別癡心妄想地想靠 constexpr 來強制程式碼「內聯」。
+ 靠 constexpr 特性,方才實作了 C++ 在介面上打造真正常數機制的可能。好好用 constexpr 來定義真・常量以及支持常量的函式。Avoid complexifying function definitions to enable their use with constexpr. 千萬別癡心妄想地想靠 constexpr 來強制程式碼「內聯」。
5.14. 整數
~~~~~~~~~~~~~~~~~~
@@ -545,13 +545,13 @@
.. tip::
- 使用巨集時要非常謹慎, 盡量以內聯函數, 列舉和常數代替之.
+ 使用巨集時要非常謹慎, 盡量以內聯函式, 列舉和常數代替之.
巨集意味著你和編譯器看到的程式碼是不同的. 這可能會導致例外行為, 尤其因為宏具有全域作用域.
-值得慶幸的是, C++ 中, 巨集不像在 C 中那麼必不可少. 以往用宏展開性能關鍵的程式碼, 現在可以用內聯函數替代. 用宏表示常數可被 ``const`` 變數代替. 用宏 "縮寫" 長變量名可被引用代替. 用宏進行條件編譯... 這個, 千萬別這麼做, 會令測試更加痛苦 (``#define`` 防止標頭檔重包含當然是個特例).
+值得慶幸的是, C++ 中, 巨集不像在 C 中那麼必不可少. 以往用宏展開性能關鍵的程式碼, 現在可以用內聯函式替代. 用宏表示常數可被 ``const`` 變數代替. 用宏 "縮寫" 長變量名可被引用代替. 用宏進行條件編譯... 這個, 千萬別這麼做, 會令測試更加痛苦 (``#define`` 防止標頭檔重包含當然是個特例).
-巨集可以做一些其他技術無法實現的事情, 在一些程式碼庫 (尤其是底層庫中) 可以看到宏的某些特性 (如用 ``#`` 字符串化, 用 ``##`` 連接等等). 但在使用前, 仔細考慮一下能不能不使用宏達到同樣的目的.
+巨集可以做一些其他技術無法實作的事情, 在一些程式碼庫 (尤其是底層庫中) 可以看到宏的某些特性 (如用 ``#`` 字符串化, 用 ``##`` 連接等等). 但在使用前, 仔細考慮一下能不能不使用宏達到同樣的目的.
下面給出的用法模式可以避免使用巨集帶來的問題; 如果你要宏, 盡可能遵守:
@@ -559,7 +559,7 @@
- 在馬上要使用時才進行 ``#define``, 使用後要立即 ``#undef``.
- 不要只是對已經存在的巨集使用#undef,選擇一個不會衝突的名稱;
- 不要試圖使用展開後會導致 C++ 建構不穩定的巨集, 不然也至少要附上文檔說明其行為.
- - 不要用 ``##`` 處理函數,類和變數的名字。
+ - 不要用 ``##`` 處理函式,類和變數的名字。
5.17. 0, ``nullptr`` 和 ``NULL``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -710,7 +710,7 @@
// 初始化列表可迭代。
for (int i : {-1, -2, -3}) {}
- // 在函數呼叫裡用列表初始化。
+ // 在函式呼叫裡用列表初始化。
void TestFunction2(vector v) {}
TestFunction2({1, 2, 3});
@@ -770,7 +770,7 @@
定義:
- Lambda 表達式是創建匿名函數對象的一種簡易途徑,常用於把函數當參數傳,例如:
+ Lambda 表達式是創建匿名函式對象的一種簡易途徑,常用於把函式當參數傳,例如:
.. code-block:: c++
@@ -778,23 +778,23 @@
return Weight(x) < Weight(y);
});
- C++11 首次提出 Lambdas, 還提供了一系列處理函數對象的工具,比如多態包裝器(polymorphic wrapper) ``std::function``.
+ C++11 首次提出 Lambdas, 還提供了一系列處理函式對象的工具,比如多態包裝器(polymorphic wrapper) ``std::function``.
優點:
- * 傳函數對象給 STL 算法,Lambdas 最簡易,可讀性也好。
- * Lambdas, ``std::functions`` 和 ``std::bind`` 可以搭配成通用回調機制(general purpose callback mechanism);寫接收有界函數為參數的函數也很容易了。
+ * 傳函式對象給 STL 算法,Lambdas 最簡易,可讀性也好。
+ * Lambdas, ``std::functions`` 和 ``std::bind`` 可以搭配成通用回調機制(general purpose callback mechanism);寫接收有界函式為參數的函式也很容易了。
缺點:
* Lambdas 的變數捕獲略旁門左道,可能會造成懸空指標。
- * Lambdas 可能會失控;層層嵌套的匿名函數難以閱讀。
+ * Lambdas 可能會失控;層層嵌套的匿名函式難以閱讀。
結論:
* 按 format 小用 lambda 表達式怡情。
* 禁用默認捕獲,捕獲都要顯式寫出來。打比方,比起 ``[=](int x) {return x + n;}``, 你該寫成 ``[n](int x) {return x + n;}`` 才對,這樣讀者也好一眼看出 ``n`` 是被捕獲的值。
- * 匿名函數始終要簡短,如果函數體超過了五行,那麼還不如起名(acgtyrant 註:即把 lambda 表達式賦值給對象),或改用函數。
+ * 匿名函式始終要簡短,如果函式體超過了五行,那麼還不如起名(acgtyrant 註:即把 lambda 表達式賦值給對象),或改用函式。
* 如果可讀性更好,就顯式寫出 lambd 的尾置返回類型,就像auto.
5.22. 樣板元程式撰寫
@@ -820,7 +820,7 @@
缺點:
- 某些 Boost 庫提倡的程式撰寫實踐可讀性差, 比如元程式撰寫和其他高級樣板技術, 以及過度 "函數化" 的程式撰寫風格.
+ 某些 Boost 庫提倡的程式撰寫實踐可讀性差, 比如元程式撰寫和其他高級樣板技術, 以及過度 "函式化" 的程式撰寫風格.
結論:
@@ -889,12 +889,12 @@
譯者(acgtyrant)筆記
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-#. 實際上,`預設參數會改變函數簽名的前提是改變了它接收的參數數量 `_,比如把 ``void a()`` 改成 ``void a(int b = 0)``, 開發者改變其程式碼的初衷也許是,在不改變「程式碼相容性」的同時,又提供了可選 int 參數的餘地,然而這終究會破壞函數指標上的相容性,畢竟函數簽名確實變了。
-#. 此外把自帶預設參數的函數地址賦值給指標時,會丟失缺省參數信息。
-#. 我還發現 `濫用預設參數會害得讀者光只看呼叫程式碼的話,會誤以為其函數接受的參數數量比實際上還要少。 `_
-#. ``friend`` 實際上只對函數/類賦予了對其所在類的訪問權限,並不是有效的宣告語句。所以除了在標頭檔類內部寫 friend 函數/類,還要在類作用域之外正式地宣告一遍,最後在對應的 ``.cc`` 文件加以定義。
+#. 實際上,`預設參數會改變函式簽名的前提是改變了它接收的參數數量 `_,比如把 ``void a()`` 改成 ``void a(int b = 0)``, 開發者改變其程式碼的初衷也許是,在不改變「程式碼相容性」的同時,又提供了可選 int 參數的餘地,然而這終究會破壞函式指標上的相容性,畢竟函式簽名確實變了。
+#. 此外把自帶預設參數的函式地址賦值給指標時,會丟失缺省參數信息。
+#. 我還發現 `濫用預設參數會害得讀者光只看呼叫程式碼的話,會誤以為其函式接受的參數數量比實際上還要少。 `_
+#. ``friend`` 實際上只對函式/類賦予了對其所在類的訪問權限,並不是有效的宣告語句。所以除了在標頭檔類內部寫 friend 函式/類,還要在類作用域之外正式地宣告一遍,最後在對應的 ``.cc`` 文件加以定義。
#. 本風格指南都強調了「友元應該定義在同一文件內,避免程式碼讀者跑到其它文件查找使用該私有成員的類」。那麼可以把其宣告放在類宣告所在的標頭檔,定義也放在類定義所在的文件。
-#. 由於友元函數/類並不是類的一部分,自然也不會是類可呼叫的公有介面,於是我主張全集中放在類的尾部,即 :ref:`private 的數據成員 `_ 之後。
+#. 由於友元函式/類並不是類的一部分,自然也不會是類可呼叫的公有介面,於是我主張全集中放在類的尾部,即 :ref:`private 的數據成員 `_ 之後。
#. `對使用 C++ 例外處理應具有怎樣的態度? `_ 非常值得一讀。
#. 注意初始化 const 對象時,必須在初始化的同時值初始化。
#. 用斷言代替無符號整數類型,深有啟發。
diff --git a/google-cpp-styleguide/scoping.rst b/google-cpp-styleguide/scoping.rst
index 5c59bd2e..6108fa55 100644
--- a/google-cpp-styleguide/scoping.rst
+++ b/google-cpp-styleguide/scoping.rst
@@ -57,7 +57,7 @@
// 命名空間的內容無需縮排
- // 此函數產生出來的 symbol 保證不會和連結時期的其他 symbol 相撞。且此 symbol
+ // 此函式產生出來的 symbol 保證不會和連結時期的其他 symbol 相撞。且此 symbol
// 只能在這個 .cc 文件中被看到。
bool UpdateInternals(Frobber* f, int newval) {
...
@@ -94,7 +94,7 @@
// .cc 文件
namespace mynamespace {
- // 函數定義都置於命名空間中
+ // 函式定義都置於命名空間中
void MyClass::Foo() {
…
}
@@ -141,7 +141,7 @@
} // namespace impl
inline void my_inline_function() {
- // 命名空間別名到一個函數或方法
+ // 命名空間別名到一個函式或方法
namespace fbz = ::foo::bar::baz;
...
}
@@ -149,37 +149,37 @@
- 禁止用內聯命名空間
-2.2. 非成員函數、靜態成員函數和全域函數
+2.2. 非成員函式、靜態成員函式和全域函式
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. tip::
- 使用靜態成員函數或命名空間內的非成員函數, 盡量不要用裸的全域函數.
+ 使用靜態成員函式或命名空間內的非成員函式, 盡量不要用裸的全域函式.
優點:
- 某些情況下, 非成員函數和靜態成員函數是非常有用的, 將非成員函數放在命名空間內可避免污染全域作用域.
+ 某些情況下, 非成員函式和靜態成員函式是非常有用的, 將非成員函式放在命名空間內可避免污染全域作用域.
缺點:
- 將非成員函數和靜態成員函數作為新類的成員或許更有意義, 當它們需要訪問外部資源或具有重要的相依性關係時更是如此.
+ 將非成員函式和靜態成員函式作為新類的成員或許更有意義, 當它們需要訪問外部資源或具有重要的相依性關係時更是如此.
結論:
- 有時, 把函數的定義同類的實例脫鉤是有益的, 甚至是必要的. 這樣的函數可以被定義成靜態成員, 或是非成員函數. 非成員函數不應相依性於外部變數, 應盡量置於某個命名空間內. 相比單純為了封裝若幹不共享任何靜態數據的靜態成員函數而創建類, 不如使用:ref:`namespaces`。
+ 有時, 把函式的定義同類的實例脫鉤是有益的, 甚至是必要的. 這樣的函式可以被定義成靜態成員, 或是非成員函式. 非成員函式不應相依性於外部變數, 應盡量置於某個命名空間內. 相比單純為了封裝若幹不共享任何靜態數據的靜態成員函式而創建類, 不如使用:ref:`namespaces`。
- 定義在同一編譯單元的函數, 被其他編譯單元直接呼叫可能會引入不必要的耦合和連結時相依性; 靜態成員函數對此尤其敏感. 可以考慮提取到新類中, 或者將函數置於獨立庫的命名空間內.
+ 定義在同一編譯單元的函式, 被其他編譯單元直接呼叫可能會引入不必要的耦合和連結時相依性; 靜態成員函式對此尤其敏感. 可以考慮提取到新類中, 或者將函式置於獨立庫的命名空間內.
- 如果你必須定義非成員函數, 又只是在 ``.cc`` 文件中使用它, 可使用匿名:ref:`namespaces`或 ``static`` 連結關鍵字 (如 ``static int Foo() {...}``) 限定其作用域.
+ 如果你必須定義非成員函式, 又只是在 ``.cc`` 文件中使用它, 可使用匿名:ref:`namespaces`或 ``static`` 連結關鍵字 (如 ``static int Foo() {...}``) 限定其作用域.
2.3. 區域變數
~~~~~~~~~~~~~~~~~~~~~~
.. tip::
- 將函數變數盡可能置於最小作用域內, 並在變量宣告時進行初始化.
+ 將函式變數盡可能置於最小作用域內, 並在變量宣告時進行初始化.
-C++ 允許在函數的任何位置宣告變數. 我們提倡在盡可能小的作用域中宣告變量, 離第一次使用越近越好. 這使得程式碼瀏覽者更容易定位變量宣告的位置, 瞭解變量的類型和初始值. 特別是,應使用初始化的方式替代宣告再賦值, 比如:
+C++ 允許在函式的任何位置宣告變數. 我們提倡在盡可能小的作用域中宣告變量, 離第一次使用越近越好. 這使得程式碼瀏覽者更容易定位變量宣告的位置, 瞭解變量的類型和初始值. 特別是,應使用初始化的方式替代宣告再賦值, 比如:
.. code-block:: c++
@@ -194,7 +194,7 @@ C++ 允許在函數的任何位置宣告變數. 我們提倡在盡可能小的
vector v = {1, 2}; // 好——v 一開始就初始化
-注意, GCC 可正確實現了 ``for (int i = 0; i < 10; ++i)`` (``i`` 的作用域僅限 ``for`` 循環內), 所以其他 ``for`` 循環中可以重新使用 ``i``. 在 ``if`` 和 ``while`` 等語句中的作用域宣告也是正確的, 如:
+注意, GCC 可正確實作了 ``for (int i = 0; i < 10; ++i)`` (``i`` 的作用域僅限 ``for`` 循環內), 所以其他 ``for`` 循環中可以重新使用 ``i``. 在 ``if`` 和 ``while`` 等語句中的作用域宣告也是正確的, 如:
.. code-block:: c++
@@ -205,7 +205,7 @@ C++ 允許在函數的任何位置宣告變數. 我們提倡在盡可能小的
.. code-block:: c++
- // 低效的實現
+ // 低效的實作
for (int i = 0; i < 1000000; ++i) {
Foo f; // 建構子和解構子分別呼叫 1000000 次!
f.DoSomething(i);
@@ -227,9 +227,9 @@ C++ 允許在函數的任何位置宣告變數. 我們提倡在盡可能小的
禁止使用 ``class`` 類型的靜態或全域變數:它們會導致難以發現的 bug 和不確定的建構和解構子呼叫順序。不過 ``constexpr`` 變量除外,畢竟它們又不涉及動態初始化或解構。
-靜態生存週期的對象,即包括了全域變數,靜態變量,靜態類成員變量和函數靜態變量,都必須是原生數據類型 (POD : Plain Old Data): 即 int, char 和 float, 以及 POD 類型的指標、陣列和結構體。
+靜態生存週期的對象,即包括了全域變數,靜態變量,靜態類成員變量和函式靜態變量,都必須是原生數據類型 (POD : Plain Old Data): 即 int, char 和 float, 以及 POD 類型的指標、陣列和結構體。
-靜態變數的建構子、解構子和初始化的順序在 C++ 中是不確定的,甚至隨著構建變化而變化,導致難以發現的 bug. 所以除了禁用類類型的全域變量,我們也不允許用函數返回值來初始化 POD 變量,除非該函數不涉及(比如 getenv() 或 getpid())不涉及任何全域變量。(函數作用域裡的靜態變量除外,畢竟它的初始化順序是有明確定義的,而且只會在指令執行到它的宣告那裡才會發生。)
+靜態變數的建構子、解構子和初始化的順序在 C++ 中是不確定的,甚至隨著構建變化而變化,導致難以發現的 bug. 所以除了禁用類類型的全域變量,我們也不允許用函式返回值來初始化 POD 變量,除非該函式不涉及(比如 getenv() 或 getpid())不涉及任何全域變量。(函式作用域裡的靜態變量除外,畢竟它的初始化順序是有明確定義的,而且只會在指令執行到它的宣告那裡才會發生。)
同理,全域和靜態變數在程式中斷時會被解構,無論所謂中斷是從 ``main()`` 返回還是對 ``exit()`` 的呼叫。析構順序正好與建構子呼叫的順序相反。但既然建構順序未定義,那麼析構順序當然也就不定了。比如,在程式結束時某靜態變量已經被析構了,但程式碼還在跑——比如其它線程——並試圖訪問它且失敗;再比如,一個靜態 string 變量也許會在一個引用了前者的其它變量析構之前被析構掉。
@@ -237,18 +237,18 @@ C++ 允許在函數的任何位置宣告變數. 我們提倡在盡可能小的
綜上所述,我們只允許 POD 類型的靜態變數,即完全禁用 ``vector`` (使用 C 陣列替代) 和 ``string`` (使用 ``const char []``)。
-如果你確實需要一個 ``class`` 類型的靜態或全域變數,可以考慮在 ``main()`` 函數或 ``pthread_once()`` 內初始化一個指標且永不回收。注意只能用 raw 指針,別用智慧指針,畢竟後者的解構子涉及到上文指出的不定順序問題。
+如果你確實需要一個 ``class`` 類型的靜態或全域變數,可以考慮在 ``main()`` 函式或 ``pthread_once()`` 內初始化一個指標且永不回收。注意只能用 raw 指針,別用智慧指針,畢竟後者的解構子涉及到上文指出的不定順序問題。
.. note:: Yang.Y 譯注:
- 上文提及的靜態變數泛指靜態生存週期的對象, 包括: 全域變量, 靜態變量, 靜態類成員變量, 以及函數靜態變量.
+ 上文提及的靜態變數泛指靜態生存週期的對象, 包括: 全域變量, 靜態變量, 靜態類成員變量, 以及函式靜態變量.
譯者 (YuleFox) 筆記
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#. ``cc`` 中的匿名命名空間可避免命名衝突, 限定作用域, 避免直接使用 ``using`` 關鍵字污染命名空間;
#. 巢狀類別符合局部使用原則, 只是不能在其他標頭檔中前置宣告, 盡量不要 ``public``;
-#. 盡量不用全域函數和全域變數, 考慮作用域和命名空間限制, 盡量單獨形成編譯單元;
+#. 盡量不用全域函式和全域變數, 考慮作用域和命名空間限制, 盡量單獨形成編譯單元;
#. 多線程中的全域變數 (含靜態成員變量) 不要使用 ``class`` 類型 (含 STL 容器), 避免不明確行為導致的 bug.
#. 作用域的使用, 除了考慮名稱污染, 可讀性之外, 主要是為降低耦合, 提高編譯/執行效率.