青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

Creative Commons License
本Blog采用 知識共享署名-非商業性使用-禁止演繹 3.0 Unported許可協議 進行許可。 —— Fox <游戲人生>

游戲人生

游戲人生 != ( 人生 == 游戲 )
站點遷移至:http://www.yulefox.com。請訂閱本博的朋友將RSS修改為http://feeds.feedburner.com/yulefox
posts - 62, comments - 508, trackbacks - 0, articles - 7

[譯]Google C++編程風格指南(三)

Posted on 2008-07-16 17:43 Fox 閱讀(4935) 評論(4)  編輯 收藏 引用 所屬分類: T技術碎語

這一篇主要提到的是類,Lippman在《Inside The C++ Object Model》第二章中對構造函數作了詳盡說明,本文中提到的幾個單詞基本仿該書中譯本侯捷先生的翻譯:

explicit:明確的

implicit:隱含的

trivial:沒有意義的

non-trivial:有意義的

 

原文地址:

類是C++中基本的代碼單元,自然被廣泛使用。本節列舉了在寫一個類時要做什么、不要做什么。

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

構造函數中只進行那些沒有實際意義的(trivial,譯者注:簡單初始化對于程序執行沒有實際的邏輯意義,因為成員變量的“有意義”的值大多不在構造函數中確定)初始化,可能的話,使用Init()方法集中初始化為有意義的(non-trivial)數據。

定義:在構造函數中執行初始化操作。

優點:排版方便,無需擔心類是否初始化。

缺點:在構造函數中執行操作引起的問題有:

1) 構造函數中不易報告錯誤,不能使用異常。

2) 操作失敗會造成對象初始化失敗,引起不確定狀態。

3) 構造函數內調用虛函數,調用不會派發到子類實現中,即使當前沒有子類化實現,將來仍是隱患。

4) 如果有人創建該類型的全局變量(雖然違背了上節提到的規則),構造函數將在main()之前被調用,有可能破壞構造函數中暗含的假設條件。例如,gflags尚未初始化。

結論:如果對象需要有意義的(non-trivial)初始化,考慮使用另外的Init()方法并(或)增加一個成員標記用于指示對象是否已經初始化成功。

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

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

定義:新建一個沒有參數的對象時,默認構造函數被調用,當調用new[](為數組)時,默認構造函數總是被調用。

優點:默認將結構體初始化為“不可能的”值,使調試更加容易。

缺點:對代碼編寫者來說,這是多余的工作。

結論:

如果類中定義了成員變量,沒有提供其他構造函數,你需要定義一個默認構造函數(沒有參數)。默認構造函數更適合于初始化對象,使對象內部狀態(internal state)一致、有效。

提供默認構造函數的原因是:如果你沒有提供其他構造函數,又沒有定義默認構造函數,編譯器將為你自動生成一個,編譯器生成的構造函數并不會對對象進行初始化。

如果你定義的類繼承現有類,而你又沒有增加新的成員變量,則不需要為新類定義默認構造函數。

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

對單參數構造函數使用C++關鍵字explicit。

定義:通常,只有一個參數的構造函數可被用于轉換(conversion,譯者注:主要指隱式轉換,下文可見),例如,定義了Foo::Foo(string name),當向需要傳入一個Foo對象的函數傳入一個字符串時,構造函數Foo::Foo(string name)被調用并將該字符串轉換為一個Foo臨時對象傳給調用函數。看上去很方便,但如果你并不希望如此通過轉換生成一個新對象的話,麻煩也隨之而來。為避免構造函數被調用造成隱式轉換,可以將其聲明為explicit。

優點:避免不合時宜的變換。

缺點:無。

結論:

所有單參數構造函數必須是明確的。在類定義中,將關鍵字explicit加到單參數構造函數前:explicit Foo(string name);

例外:在少數情況下,拷貝構造函數可以不聲明為explicit;特意作為其他類的透明包裝器的類。類似例外情況應在注釋中明確說明。

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

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

定義:通過拷貝新建對象時可使用拷貝構造函數(特別是對象的傳值時)。

優點:拷貝構造函數使得拷貝對象更加容易,STL容器要求所有內容可拷貝、可賦值。

缺點:C++中對象的隱式拷貝是導致很多性能問題和bugs的根源。拷貝構造函數降低了代碼可讀性,相比按引用傳遞,跟蹤按值傳遞的對象更加困難,對象修改的地方變得難以捉摸。

結論:

大量的類并不需要可拷貝,也不需要一個拷貝構造函數或賦值操作(assignment operator)。不幸的是,如果你不主動聲明它們,編譯器會為你自動生成,而且是public的。

可以考慮在類的private中添加空的(dummy)拷貝構造函數和賦值操作,只有聲明,沒有定義。由于這些空程序聲明為private,當其他代碼試圖使用它們的時候,編譯器將報錯。為了方便,可以使用宏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。

在C++中,關鍵字struct和class幾乎含義等同,我們為其人為添加語義,以便為定義的數據類型合理選擇使用哪個關鍵字。

struct被用在僅包含數據的消極對象(passive objects)上,可能包括有關聯的常量,但沒有存取數據成員之外的函數功能,而存取功能通過直接訪問實現而無需方法調用,這兒提到的方法是指只用于處理數據成員的,如構造函數、析構函數、Initialize()、Reset()、Validate()。

如果需要更多的函數功能,class更適合,如果不確定的話,直接使用class。

如果與STL結合,對于仿函數(functors)和特性(traits)可以不用class而是使用struct。

注意:類和結構體的成員變量使用不同的命名規則。

6. 繼承(Inheritance

使用組合(composition,譯者注,這一點也是GoF在《Design Patterns》里反復強調的)通常比使用繼承更適宜,如果使用繼承的話,只使用公共繼承。

定義:當子類繼承基類時,子類包含了父基類所有數據及操作的定義。C++實踐中,繼承主要用于兩種場合:實現繼承(implementation inheritance),子類繼承父類的實現代碼;接口繼承(interface inheritance),子類僅繼承父類的方法名稱。

優點:實現繼承通過原封不動的重用基類代碼減少了代碼量。由于繼承是編譯時聲明(compile-time declaration),編碼者和編譯器都可以理解相應操作并發現錯誤。接口繼承可用于程序上增強類的特定API的功能,在類沒有定義API的必要實現時,編譯器同樣可以偵錯。

缺點:對于實現繼承,由于實現子類的代碼在父類和子類間延展,要理解其實現變得更加困難。子類不能重寫父類的非虛函數,當然也就不能修改其實現。基類也可能定義了一些數據成員,還要區分基類的物理輪廓(physical layout)

結論:

所有繼承必須是public的,如果想私有繼承的話,應該采取包含基類實例作為成員的方式作為替代。

不要過多使用實現繼承,組合通常更合適一些。努力做到只在“是一個”("is-a",譯者注,其他"has-a"情況下請使用組合)的情況下使用繼承:如果Bar的確“是一種”Foo,才令Bar是Foo的子類。

必要的話,令析構函數為virtual,必要是指,如果該類具有虛函數,其析構函數應該為虛函數。

譯者注:至于子類沒有額外數據成員,甚至父類也沒有任何數據成員的特殊情況下,析構函數的調用是否必要是語義爭論,從編程設計規范的角度看,在含有虛函數的父類中,定義虛析構函數絕對必要。

限定僅在子類訪問的成員函數為protected,需要注意的是數據成員應始終為私有。

當重定義派生的虛函數時,在派生類中明確聲明其為virtual。根本原因:如果遺漏virtual,閱讀者需要檢索類的所有祖先以確定該函數是否為虛函數(譯者注,雖然不影響其為虛函數的本質)

7. 多重繼承(Multiple Inheritance

真正需要用到多重實現繼承(multiple implementation inheritance)的時候非常少,只有當最多一個基類中含有實現,其他基類都是以Interface為后綴的純接口類時才會使用多重繼承。

定義:多重繼承允許子類擁有多個基類,要將作為純接口的基類和具有實現的基類區別開來。

優點:相比單繼承,多重實現繼承可令你重用更多代碼。

缺點:真正需要用到多重實現繼承的時候非常少,多重實現繼承看上去是不錯的解決方案,通常可以找到更加明確、清晰的、不同的解決方案。

結論:只有當所有超類(superclass)除第一個外都是純接口時才能使用多重繼承。為確保它們是純接口,這些類必須以Interface為后綴。

注意:關于此規則,Windows下有種例外情況(譯者注,將在本譯文最后一篇的規則例外中闡述)。

8. 接口(Interface

接口是指滿足特定條件的類,這些類以Interface為后綴(非必需)。

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

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

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

3) 沒有定義任何構造函數。如果有,也不含參數,并且為protected;

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

接口類不能被直接實例化,因為它聲明了純虛函數。為確保接口類的所有實現可被正確銷毀,必須為之聲明虛析構函數(作為第1條規則的例外,析構函數不能是純虛函數)。具體細節可參考Stroustrup的《The C++ Programming Language, 3rd edition》第12.4節。

優點:以Interface為后綴可令他人知道不能為該接口類增加實現函數或非靜態數據成員,這一點對于多重繼承尤其重要。另外,對于Java程序員來說,接口的概念已經深入人心。

缺點:Interface后綴增加了類名長度,為閱讀和理解帶來不便,同時,接口特性作為實現細節不應暴露給客戶。

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

9. 操作符重載(Operator Overloading

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

定義:一個類可以定義諸如+、/等操作符,使其可以像內建類型一樣直接使用。

優點:使代碼看上去更加直觀,就像內建類型(如int)那樣,重載操作符使那些Equals()、Add()等黯淡無光的函數名好玩多了。為了使一些模板函數正確工作,你可能需要定義操作符。

缺點:雖然操作符重載令代碼更加直觀,但也有一些不足

1) 混淆直覺,讓你誤以為一些耗時的操作像內建操作那樣輕巧;

2) 查找重載操作符的調用處更加困難,查找Equals()顯然比同等調用==容易的多;

3) 有的操作符可以對指針進行操作,容易導致bugs,Foo + 4做的是一件事,而&Foo + 4可能做的是完全不同的另一件事,對于二者,編譯器都不會報錯,使其很難調試;

4) 重載還有令你吃驚的副作用,比如,重載操作符&的類不能被前置聲明。

結論:

一般不要重載操作符,尤其是賦值操作(operator=)比較陰險,應避免重載。如果需要的話,可以定義類似Equals()、CopyFrom()等函數。

然而,極少數情況下需要重載操作符以便與模板或“標準”C++類銜接(如operator<<(ostream&, const T&)),如果被證明是正當的尚可接受,但你要盡可能避免這樣做。尤其是不要僅僅為了在STL容器中作為key使用就重載operator==或operator<,取而代之,你應該在聲明容器的時候,創建相等判斷和大小比較的仿函數類型。

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

參考拷貝構造函數函數重載

10. 存取控制(Access Control

將數據成員私有化,并提供相關存取函數,如定義變量foo_及取值函數foo()、賦值函數set_foo()。

存取函數的定義一般內聯在頭文件中。

參考繼承函數命名

11. 聲明次序(Declaration Order

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

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

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

1) typedefs和enums;

2) 常量;

3) 構造函數;

4) 析構函數;

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

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

宏DISALLOW_COPY_AND_ASSIGN置于private:塊之后,作為類的最后部分。參考拷貝構造函數

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

不要將大型函數內聯到類的定義中,通常,只有那些沒有特別意義的或者性能要求高的,并且是比較短小的函數才被定義為內聯函數。更多細節參考譯文第一篇的內聯函數

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

傾向于選擇短小、凝練的函數。

長函數有時是恰當的,因此對于函數長度并沒有嚴格限制。如果函數超過40行,可以考慮在不影響程序結構的情況下將其分割一下。

即使一個長函數現在工作的非常好,一旦有人對其修改,有可能出現新的問題,甚至導致難以發現的bugs。使函數盡量短小、簡單,便于他人閱讀和修改代碼。

在處理代碼時,你可能會發現復雜的長函數,不要害怕修改現有代碼:如果證實這些代碼使用、調試困難,或者你需要使用其中的一小塊,考慮將其分割為更加短小、易于管理的若干函數。

______________________________________

譯者:關于類的注意事項,總結一下:

1. 不在構造函數中做太多邏輯相關的初始化;

2. 編譯器提供的默認構造函數不會對變量進行初始化,如果定義了其他構造函數,編譯器不再提供,需要編碼者自行提供默認構造函數;

3. 為避免隱式轉換,需將單參數構造函數聲明為explicit;

4. 為避免拷貝構造函數、賦值操作的濫用和編譯器自動生成,可目前聲明其為private且無需實現;

5. 僅在作為數據集合時使用struct;

6. 組合>實現繼承>接口繼承>私有繼承,子類重載的虛函數也要聲明virtual關鍵字,雖然編譯器允許不這樣做;

7. 避免使用多重繼承,使用時,除一個基類含有實現外,其他基類均為純接口;

8. 接口類類名以Interface為后綴,除提供帶實現的虛析構函數、靜態成員函數外,其他均為純虛函數,不定義非靜態數據成員,不提供構造函數,提供的話,聲明為protected;

9. 為降低復雜性,盡量不重載操作符,模板、標準類中使用時提供文檔說明;

10. 存取函數一般內聯在頭文件中;

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

12. 函數體盡量短小、緊湊,功能單一。

Feedback

# re: [譯]Google C++編程風格指南(三)  回復  更多評論   

2008-07-17 18:05 by 陳梓瀚(vczh)
構造函數可以throw,不知道為什么不能用異常。構造函數失敗的時候要讓那個對象從此不能被訪問到才對,所以用throw。

# re: [譯]Google C++編程風格指南(三)  回復  更多評論   

2008-07-18 10:06 by Fox
這一點在下一篇C++特性中有對禁止使用C++異常的說明,不僅僅是針對構造函數,是針對整個coding。
不管怎么說,都只是一種編程約束,有利必有弊,感覺更多是從軟件工程的角度給出的約束。

# re: [譯]Google C++編程風格指南(三)  回復  更多評論   

2008-07-19 12:52 by 陳梓瀚(vczh)
原來是文章中的c++不是c++,只是more powerful c而已。

throw的確是有利有弊的,不過禁止光了那也不好。當異常真的需要在調用堆棧中一級以及傳播出來的時候,自己搞是很慘的。

# re: [譯]Google C++編程風格指南(三)  回復  更多評論   

2008-07-19 13:48 by Fox
恩,看過這個指南之后,感覺是因為Google的項目中大多沒有使用高級C++特性,所以對于很多特性都是盡量避免使用,對于自己開發的項目制定一個自己的風格,大家一起遵循,也基本是從軟件工程的角度,我比較贊成在底層模塊中使用,上層邏輯可以少用即可。
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            亚洲毛片av| 久久国产视频网站| 午夜欧美电影在线观看| 亚洲免费一在线| 在线精品国产成人综合| 日韩视频在线免费| 国产在线精品一区二区中文| 欧美国产日韩一区二区三区| 欧美日韩免费观看一区=区三区| 亚洲欧美国产制服动漫| 麻豆精品91| 欧美一区二区三区在线视频| 欧美激情第三页| 久久久综合网| 国产精品高潮呻吟久久av无限| 欧美成人免费全部| 国产乱码精品一区二区三| 亚洲激情av在线| 国产精品女同互慰在线看| 亚洲电影在线播放| 国产一区二区三区最好精华液| 亚洲免费久久| 最新国产成人av网站网址麻豆| 午夜精品久久久99热福利| 一本大道av伊人久久综合| 久久久国产视频91| 欧美一区二区三区在线观看| 欧美日韩一区二区视频在线观看| 欧美高清视频在线播放| 国内精品久久国产| 午夜一级久久| 性欧美1819sex性高清| 欧美理论电影在线播放| 欧美激情国产高清| 永久免费精品影视网站| 午夜宅男久久久| 欧美亚洲一区三区| 国产精品久久久久久久久久久久 | 亚洲综合色激情五月| 亚洲乱码国产乱码精品精天堂 | 亚洲性图久久| 欧美福利电影在线观看| 欧美国产91| 亚洲高清资源| 媚黑女一区二区| 欧美大学生性色视频| 尤物99国产成人精品视频| 久久av最新网址| 久久久在线视频| 国产一区二区三区日韩欧美| 亚洲欧美视频在线| 欧美综合第一页| 国产网站欧美日韩免费精品在线观看| 亚洲一区二区三区四区五区黄| 亚洲欧美不卡| 国产精一区二区三区| 欧美一级大片在线观看| 久久频这里精品99香蕉| 一区二区三区在线不卡| 美女国内精品自产拍在线播放| 午夜免费日韩视频| 老司机久久99久久精品播放免费| 蜜臀va亚洲va欧美va天堂| 欧美视频在线观看免费| 亚洲国产视频直播| 久久综合狠狠综合久久综合88| av不卡免费看| 欧美日韩伦理在线| 一片黄亚洲嫩模| 欧美一级二区| 亚洲精品国产精品国产自| 久久成年人视频| 国产欧美一区二区三区久久| 亚洲人精品午夜| 麻豆成人在线观看| 久久精品在线播放| 国产网站欧美日韩免费精品在线观看 | 国产欧美日韩视频一区二区三区| 一本色道久久综合亚洲精品按摩 | 亚洲国产日韩一区| 久久久www免费人成黑人精品| 亚洲欧美日韩在线不卡| 国产精品爱啪在线线免费观看 | 亚洲视频欧美视频| 亚洲视频免费在线| 先锋资源久久| 国产精品电影网站| 亚洲天堂免费观看| 在线亚洲国产精品网站| 欧美天堂亚洲电影院在线播放| 欧美人与禽猛交乱配| 亚洲国产欧美日韩另类综合| 欧美成人影音| 欧美激情视频网站| 亚洲一区二区三区免费观看| 亚洲一二三区精品| 在线不卡a资源高清| 亚洲国产精品毛片| 国产精品久久久爽爽爽麻豆色哟哟| 先锋a资源在线看亚洲| 欧美一区二区在线视频| 亚洲第一福利视频| 一区二区三区视频观看| 一区二区亚洲精品国产| 最新精品在线| 伊人婷婷欧美激情| 亚洲一区在线直播| 亚洲电影免费在线观看| 日韩一二三在线视频播| 亚洲欧洲一区二区三区在线观看 | 一区二区三区免费看| 韩日成人av| 在线视频亚洲欧美| 最新成人在线| 麻豆亚洲精品| 久久亚洲精选| 国产精品综合不卡av| 一本色道久久综合亚洲精品不卡 | 一区二区日韩| 久久一区中文字幕| 久久精品理论片| 国产欧美日韩综合精品二区| 99精品国产在热久久下载| 日韩亚洲欧美中文三级| 免费视频一区| 亚洲国产日韩欧美一区二区三区| 亚洲电影专区| 欧美不卡一卡二卡免费版| 亚洲国产三级在线| 99精品久久久| 亚洲欧美日韩国产中文在线| 亚洲欧美一区二区激情| 国产精品久久久久影院色老大 | 国产精品99久久久久久久vr| 欧美久久久久久| 亚洲在线播放| 乱中年女人伦av一区二区| 亚洲第一视频网站| 欧美久久电影| 性欧美大战久久久久久久久| 久久综合伊人77777尤物| 亚洲日本电影| 国产精品一区亚洲| 美国成人毛片| 亚洲综合色自拍一区| 欧美成人午夜激情| 性欧美暴力猛交另类hd| 亚洲国产小视频在线观看| 欧美日韩一区二区免费视频| 久久精品亚洲| 亚洲愉拍自拍另类高清精品| 亚洲国产成人av| 久久久免费精品视频| 亚洲一本大道在线| 亚洲精品美女久久7777777| 国产亚洲精品一区二区| 欧美午夜不卡视频| 欧美aaaaaaaa牛牛影院| 久久久www成人免费精品| 亚洲欧美日韩国产另类专区| 一本色道久久综合亚洲二区三区| 欧美aaa级| 久久综合国产精品台湾中文娱乐网| 亚洲欧美制服中文字幕| 日韩一区二区精品| 亚洲精品日本| 亚洲精品乱码久久久久久黑人| 精品av久久久久电影| 国语自产精品视频在线看8查询8| 国产一区在线播放| 国产有码在线一区二区视频| 国产亚洲一区在线| 国内精品**久久毛片app| 韩日午夜在线资源一区二区| 国产日韩欧美综合| 激情久久婷婷| 亚洲精选一区| 午夜精品久久| 久久精品99国产精品| 久久精品视频在线看| 欧美成人精品三级在线观看| 最新中文字幕一区二区三区| 亚洲高清成人| 在线亚洲高清视频| 欧美一级欧美一级在线播放| 久久精品视频免费观看| 欧美成年人视频网站| 亚洲视频日本| 久久看片网站| 欧美日韩在线视频一区二区| 国产伦精品一区二区三区视频黑人| 国外成人在线| 亚洲制服欧美中文字幕中文字幕| 午夜日韩视频| 91久久久一线二线三线品牌| 亚洲视频一区二区在线观看 | 亚洲激情av在线| 亚洲在线电影| 欧美日韩喷水| 91久久久久久|