国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學(xué)院 > 開發(fā)設(shè)計(jì) > 正文

C++箴言:理解Terminology術(shù)語

2019-11-17 05:11:06
字體:
供稿:網(wǎng)友

  這是一個(gè)所有程序員都應(yīng)該了解的小型的 C++ 詞匯表。下面的條目都足夠重要,值得我們對它們的含義務(wù)必取得完全一致。

  聲明(declaration)告訴編譯器關(guān)于某物的名字和類型,但它省略了某些細(xì)節(jié)。以下這些都是聲明:

extern int x; // object declaration

std::size_t numDigits(int number); // function declaration

class Widget; // class declaration

template<typename T> // template declaration
class GraphNode; // (see Item 42 for info on
// the use of "typename")

  注重即使是內(nèi)建類型,我還是更喜歡將整數(shù)看作一個(gè) "object",某些人將 "object" 這個(gè)名字保留給用戶定義類型,但我不是他們中的一員。再有就是注重函數(shù) numDigits 的返回類型是 std::size_t,也就是說,namespace std 中的 size_t 類型。這個(gè) namespace 是 C++ 標(biāo)準(zhǔn)庫中每一樣?xùn)|西實(shí)際所在的地方。但是,因?yàn)?C 標(biāo)準(zhǔn)庫(嚴(yán)謹(jǐn)?shù)卣f,來自于 C89)在 C++ 中也能使用,從 C 繼續(xù)來的符號(諸如 size_t)可能存在于全局范圍,std 內(nèi)部,或兩者都有,這依靠于哪一個(gè)頭文件被 #included。在本書中,我假設(shè) C++ 頭文件被 #included,這也就是為什么我用 std::size_t 代替 size_t 的原因。當(dāng)行文中涉及到標(biāo)準(zhǔn)庫組件時(shí),我一般不再提及 std,這依靠于你認(rèn)可類似 size_t,vector,以及 cout 之類的東西都在 std 中,在示例代碼中,我總是包含 std,因?yàn)檎嬲拇a沒有它將無法編譯。

  順便說一下,size_t 僅僅是某些供 C++ 對某物計(jì)數(shù)時(shí)使用的 unsigned 類型的 typedef(例如,一個(gè)基于 char* 的 string 中字符的個(gè)數(shù),一個(gè) STL 容器中元素的個(gè)數(shù),等等)。它也是 vector,deque,以及 string 的 Operator[] 函數(shù)所持有的類型,這是一個(gè)在 Item 3 中定義我們自己的 operator[] 函數(shù)時(shí)將要遵守的慣例。

  每一個(gè)函數(shù)的聲明都表明了它的識別標(biāo)志(signature),也就是它的參數(shù)和返回類型。一個(gè)函數(shù)的識別標(biāo)志(signature)與它的類型相同。對于 numDigits 的情況,識別標(biāo)志(signature)是 std::size_t (int),也就是說,“函數(shù)持有一個(gè) int,并返回一個(gè) std::size_t”。官方的“識別標(biāo)志(signature)”的 C++ 定義排除了函數(shù)的返回類型,但是在本書中,將返回類型考慮為識別標(biāo)志的一部分更加有用。

  定義(definition)為編譯器提供在聲明時(shí)被省略的細(xì)節(jié)。對于一個(gè)對象,定義是編譯器為對象留出內(nèi)存的地方。對于一個(gè)函數(shù)或一個(gè)函數(shù)模板,定義提供代碼本體。對于一個(gè)類或一個(gè)類模板,定義列出了類或者模板的成員:

int x; // object definition

std::size_t numDigits(int number) // function definition.
{
  // (This function returns
  std::size_t digitsSoFar = 1; // the number of digits
  // in its parameter.)
  while ((number /= 10) != 0) ++digitsSoFar;
  return digitsSoFar;
}

class Widget {
  // class definition
  public:
   Widget();
   ~Widget();
  ...
};

template<typename T> // template definition
class GraphNode {
public:
  GraphNode();
  ~GraphNode();
  ...
};

  初始化(Initialization)是設(shè)定一個(gè)對象的第一個(gè)值的過程。對于用戶定義類型的對象,初始化通過構(gòu)造函數(shù)完成任務(wù)。缺省構(gòu)造函數(shù)(default constrUCtor)就是不需要任何引數(shù)(arguments)就可以調(diào)用的構(gòu)造函數(shù)。這樣的一個(gè)構(gòu)造函數(shù)既可以是沒有參數(shù)(parameters),也可以是每一個(gè)參數(shù)都有缺省值:

class A {
public:
  A(); // default constructor
};

class B {
public:
  eXPlicit B(int x = 0, bool b = true); // default constructor; see below
}; // for info on "explicit"

class C {
public:
  explicit C(int x); // not a default constructor
};

  這里 B 和 C 的構(gòu)造函數(shù)都被聲明為 explicit(顯式的)。這是為了防止它們被用來執(zhí)行隱式類型轉(zhuǎn)換(implicit type conversions),雖然他們還可以被用于顯示類型轉(zhuǎn)換(explicit type conversions):

void doSomething(B bObject); // a function taking an object of
// type B

B bObj1; // an object of type B

doSomething(bObj1); // fine, passes a B to doSomething

B bObj2(28); // fine, creates a B from the int 28
// (the bool defaults to true)

doSomething(28); // error! doSomething takes a B,
// not an int, and there is no
// implicit conversion from int to B

doSomething(B(28)); // fine, uses the B constructor to
// explicitly convert (i.e., cast) the
// int to a B for this call. (See
// Item 27 for info on casting.)

  構(gòu)造函數(shù)被聲明為 explicit(顯式的)通常比 non-explicit(非顯式)的更可取,因?yàn)樗鼈兛梢苑乐咕幾g器執(zhí)行意外的(經(jīng)常是無意識的)類型轉(zhuǎn)換。除非我有一個(gè)好的理由答應(yīng)一個(gè)構(gòu)造函數(shù)被用于隱式類型轉(zhuǎn)換(implicit type conversions),否則就將它聲明為 explicit(顯式的)。我希望你能遵循同樣的方針。

  構(gòu)造函數(shù)被聲明為 explicit(顯式的)通常比 non-explicit(非顯式)的更可取,因?yàn)樗鼈兛梢苑乐咕幾g器執(zhí)行意外的(經(jīng)常是無意識的)類型轉(zhuǎn)換。除非我有一個(gè)好的理由答應(yīng)一個(gè)構(gòu)造函數(shù)被用于隱式類型轉(zhuǎn)換(implicit type conversions),否則就將它聲明為 explicit(顯式的)。我希望你能遵循同樣的方針。

  請注重我是如何突出上面的示例代碼中的強(qiáng)制轉(zhuǎn)換(cast)的。貫穿本書,我用這樣的突出引導(dǎo)你注重那些應(yīng)該注重的材料。(我也突出章節(jié)號碼,但那僅僅是因?yàn)槲蚁胱屗每匆恍#?br />
  拷貝構(gòu)造函數(shù)(copy constructor)被用來以一個(gè)對象來初始化同類型的另一個(gè)對象,拷貝賦值運(yùn)算符(copy assignment operator)被用來將一個(gè)對象中的值拷貝到同類型的另一個(gè)對象中:

class Widget {
public:
  Widget(); // default constructor
  Widget(const Widget& rhs); // copy constructor
  Widget& operator=(const Widget& rhs); // copy assignment operator
  ...
};
Widget w1; // invoke default constructor
Widget w2(w1); // invoke copy constructor
w1 = w2; // invoke copy
// assignment operator

  當(dāng)你看到什么東西看起來像一個(gè)賦值的話,要仔細(xì)閱讀,因?yàn)?"=" 在語法上還可以被用來調(diào)用拷貝構(gòu)造函數(shù):

Widget w3 = w2; // invoke copy constructor!
  幸運(yùn)的是,拷貝構(gòu)造函數(shù)很輕易從拷貝賦值中區(qū)別出來。假如一個(gè)新的對象被定義(就象上面那行代碼中的 w3),一個(gè)構(gòu)造函數(shù)必須被調(diào)用;它不可能是一個(gè)賦值。假如沒有新的對象被定義(就象上面那行 "w1 = w2" 代碼中),沒有構(gòu)造函數(shù)能被調(diào)用,所以它就是一個(gè)賦值。

  拷貝構(gòu)造函數(shù)是一個(gè)非凡重要的函數(shù),因?yàn)樗x一個(gè)對象如何通過傳值的方式被傳遞。例如,考慮這個(gè):

bool hasAcceptableQuality(Widget w);

...
Widget aWidget;
if (hasAcceptableQuality(aWidget)) ...

  參數(shù) w 通過傳值的方式被傳遞給 hasAcceptableQuality,所以在上面的調(diào)用中,aWidget 被拷貝給 w。拷貝動作通過 Widget 的拷貝構(gòu)造函數(shù)被執(zhí)行。通過傳值方式傳遞意味著“調(diào)用拷貝構(gòu)造函數(shù)”。(無論如何,通過傳值方式傳遞用戶定義類型通常是一個(gè)不好的想法,傳引用給 const 通常是更好的選擇。) 更多文章 更多內(nèi)容請看C/C++技術(shù)專題專題,或
  STL 是標(biāo)準(zhǔn)模板庫(Standard Template Library),作為 C++ 的標(biāo)準(zhǔn)庫的一部分,致力于容器(containers)(例如,vector,list,set,map,等等),迭代器(iterators)(例如,vector<int>::iterator,set<string>::iterator,等等),算法(algorithms)(例如,
for_each,find,sort,等等),以及相關(guān)機(jī)能。相關(guān)機(jī)能中的很多都通過函數(shù)對象(function objects)——行為表現(xiàn)類似于函數(shù)的對象——提供。這樣的對象來自于重載了 operator() ——函數(shù)調(diào)用運(yùn)算符——的類,假如你不熟悉 STL,在讀本書的時(shí)候,你應(yīng)該有一本像樣的參考手冊備查,因?yàn)閷τ谖襾碚f STL 太有用了,以至于不能不利用它。一但你用了一點(diǎn)點(diǎn),你也會有同樣的感覺。

  從 java 或 C# 那樣的語言來到 C++ 的程序員可能會對未定義行為(undefined behavior)的概念感到吃驚。因?yàn)楦鞣N各樣的原因,C++ 中的一些結(jié)構(gòu)成分(constructs)的行為沒有確切的定義:你不能可靠地預(yù)知運(yùn)行時(shí)會發(fā)生什么。這里是兩個(gè)帶有未定義行為的代碼的例子:

int *p = 0; // p is a null pointer

std::cout << *p; // dereferencing a null pointer
// yields undefined behavior
char name[] = "Darla"; // name is an array of size 6 (don’t
// forget the trailing null!)

char c = name[10]; // referring to an invalid array index
// yields undefined behavior

  為了強(qiáng)調(diào)未定義行為的結(jié)果是不可預(yù)言而且可能是令人討厭的,有經(jīng)驗(yàn)的 C++ 程序員經(jīng)常說帶有未定義行為的程序能(can)刪除你的硬盤。這是真的:一個(gè)帶有未定義行為的程序可以(could)刪除你的硬盤。只不過可能性不太大。更可能的是那個(gè)程序的表現(xiàn)反復(fù)無常,有時(shí)會運(yùn)行正常,有時(shí)會徹底完蛋,還有時(shí)會產(chǎn)生錯(cuò)誤的結(jié)果。有實(shí)力的 C++ 程序員能以最佳狀態(tài)避開未定義行為。本書中,我會指出許多你必須要注重它的地方。

  另一個(gè)可能把從其它語言轉(zhuǎn)到 C++ 的程序員搞糊涂的條目是接口(interface)。Java 和 .NET 的語言都將接口作為一種語言要素,但是在 C++ 中沒有這種事。當(dāng)我使用條目“接口(interface)”時(shí),一般情況下我說的是一個(gè)函數(shù)的識別標(biāo)志,是一個(gè)類的可訪問元素(例如,一個(gè)類的 "public interface","PRotected interface",或 "private interface"),或者是對一個(gè)模板的類型參數(shù)來說必須合法的表達(dá)式。也就是說,我是作為一個(gè)相當(dāng)普遍的設(shè)計(jì)概念來談?wù)摻涌冢╥nterface)的。

  客戶(client)是使用你寫的代碼(一般是接口(interfaces))的某人或某物。例如,一個(gè)函數(shù)的客戶就是它的用戶:調(diào)用這個(gè)函數(shù)(或持有它的地址)的代碼的片段以及寫出和維護(hù)這樣的代碼的人。類或者模板的客戶是使用這個(gè)類或模板的軟件的部件,以及寫出和維護(hù)那些代碼的程序員。在討論客戶的時(shí)候,我一般指向程序員,因?yàn)槌绦騿T會被困擾和誤導(dǎo),或者因?yàn)椴缓玫慕涌诙鵁馈5麄儗懙拇a卻不會。

  你也許不習(xí)慣于為客戶著想,但是我會用大量的時(shí)間試圖說服你:你應(yīng)該盡你所能使他們的生活更輕松。記住,你也是一個(gè)其他人開發(fā)的軟件的客戶。難道你不希望那些人為你把事情弄得輕松些嗎?除此之外,在某種程度上,你幾乎肯定能發(fā)現(xiàn)你自己處在了你自己的客戶的位置上(也就是說,使用你寫的代碼),而這個(gè)時(shí)候,你會為你在開發(fā)你的接口時(shí)在頭腦中保持了對客戶的關(guān)心而感到興奮。

  我經(jīng)常掩蓋函數(shù)和函數(shù)模板之間以及類和類模板之間的區(qū)別。那是因?yàn)閷ζ渲幸粋€(gè)確定的事對另一個(gè)經(jīng)常也可以確定。假如不是這樣,我會區(qū)別對待類,函數(shù),以及由類和函數(shù)產(chǎn)生的模板。

  在代碼注釋中提到構(gòu)造函數(shù)和析構(gòu)函數(shù)時(shí),我有時(shí)使用縮寫形式 ctor 和 dtor。

  Naming Conventions 命名慣例

  我試圖為對象,類,函數(shù),模板等選擇意味深長的名字,但是在我的某些名字后面的含義可能不會立即顯現(xiàn)出來。例如,我非凡喜歡的兩個(gè)參數(shù)名字是 lhs 和 rhs。它們分別代表 "left-hand side" 和 "right-hand side"。我經(jīng)常用它們作為實(shí)現(xiàn)二元運(yùn)算符的函數(shù)(例如,operator== 和 operator*)的參數(shù)名。例如,假如 a 和 b 是代表有理數(shù)的對象,而且假如 Rational 對象能通過一個(gè)非成員的 operator* 函數(shù)相乘(Item 24 中解釋的很可能就是這種情況),表達(dá)式

a * b
  與函數(shù)調(diào)用

operator*(a,b)
  就是等價(jià)的。

  我也這樣聲明 operator*過:

const Rational operator*(const Rational& lhs, const Rational& rhs);
  你可以看到,左手操作數(shù)(left-hand operand)a 在函數(shù)內(nèi)部以 lhs 的面目出現(xiàn),而右手操作數(shù)(right-hand operand)b 以 rhs 的面目出現(xiàn)。

  對于成員函數(shù)左手參數(shù)(left-hand argument)表現(xiàn)為 this 指針,所以有時(shí)候我單獨(dú)使用參數(shù)名 rhs。
你可能已經(jīng)在第 5 頁中某些 Widget 成員函數(shù)的聲明(本文介紹拷貝構(gòu)造函數(shù)的那一段中的例子——譯者注)中注重到了這一點(diǎn)。這一點(diǎn)提醒了我。我經(jīng)常在示例中使用 Widget 類。"Widget" 并不意味著什么東西。它僅僅是在我需要一個(gè)示例類的名字的時(shí)候不時(shí)地使用一下的名字。它和 GUI 工具包中的 widgets 沒有任何關(guān)系。

  我經(jīng)常遵循這個(gè)規(guī)則為指針命名:一個(gè)指向類型 T 的對象的指針被稱為 pt,"pointer to T"。以下是例子:

Widget *pw; // pw = ptr to Widget

class Airplane;
Airplane *pa; // pa = ptr to Airplane
class GameCharacter;
GameCharacter *pgc; // pgc = ptr to GameCharacter

  我對引用使用類似的慣例:rw 可以認(rèn)為是一個(gè)引向 Widget 的引用,而 ra 是一個(gè)引向 Airplane 的引用。

  在我討論成員函數(shù)的時(shí)候我偶然會使用名字 mf。

  Threading Considerations 對線程的考慮

  作為一種語言,C++ 沒有線程的概念——實(shí)際上,是沒有任何一種并發(fā)的概念。對于 C++ 標(biāo)準(zhǔn)庫也是同樣如此。就 C++ 涉及的范圍而言,多線程編程并不存在。

  而且至今它們依然如此。我致力于讓此書基于標(biāo)準(zhǔn)的,可移植的 C++,但我也不能對線程安全(thread safety)已成為很多程序員所面臨的一個(gè)問題的事實(shí)視而不見。我對付這個(gè)標(biāo)準(zhǔn) C++ 和現(xiàn)實(shí)之間的裂痕的方法就是指出某處的 C++ 結(jié)構(gòu)成分(constructs)以我的分析很可能在多線程環(huán)境中引起問題的地方。這樣不但不會使本書成為一本用 C++ 進(jìn)行多線程編程的書。反而,它更會使本書在相當(dāng)程度上成為這樣一本 C++ 編程的書:將自己在很大程度上限制于單線程考慮,承認(rèn)多線程的存在,并試圖指出有線程意識的程序員需要非凡當(dāng)心評估我提供的建議的地方。

  假如你不熟悉多線程編程或者不必為此擔(dān)心,你可以忽略我關(guān)于線程的討論。假如你正在編寫一個(gè)多線程的應(yīng)用或庫,無論如何,請記住我的評注和并將它作為你使用 C++ 時(shí)需要致力去解決的問題的起點(diǎn)。

  TR1 and Boost TR1 和 Boost

  你會發(fā)現(xiàn)提及 TR1 和 Boost 的地方遍及整個(gè)系列。它們每一個(gè)都專門在某些細(xì)節(jié)上進(jìn)行描述,但是,不幸的是,這些都在整個(gè)系列的最后。(他們在那里是因?yàn)槟菢痈靡恍掖_實(shí)試過很多其它的地方。)假如你愿意,但是假如你更喜歡從本書的起始處而不是結(jié)尾處開始,以下摘要會對你有所幫助:

  ·TR1 ("Technical Report 1") 是被加入 C++ 標(biāo)準(zhǔn)庫的新機(jī)能的規(guī)格說明書。這些機(jī)能以新的類和函數(shù)模板的形式提供了諸如哈希表(hash tables),引用計(jì)數(shù)智能指針(reference-counting smart pointers),正則表達(dá)式(regular expressions),等等。所有的 TR1 組件都位于嵌套在 namespace std 內(nèi)部的 namespace tr1 內(nèi)。

  ·Boost 是一個(gè)組織和一個(gè)網(wǎng)站 (http://boost.org) 提供的可移植的,經(jīng)過同行評審的,開源的 C++ 庫。大多數(shù) TR1 機(jī)能都基于 Boost 的工作,而且直到編譯器廠商在他們的 C++ 庫發(fā)行版中包含 TR1 之前,Boost 網(wǎng)站很可能會保持開發(fā)者尋找 TR1 實(shí)現(xiàn)的第一站的地位。Boost 提供的東西比用于 TR1 的更多,無論如何,在很多情況下,它還是值得去了解一下的。 更多文章 更多內(nèi)容請看C/C++技術(shù)專題專題,或

發(fā)表評論 共有條評論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 寿阳县| 饶阳县| 南华县| 普陀区| 大冶市| 壶关县| 富川| 开封市| 同德县| 珠海市| 民勤县| 鹤峰县| 镇安县| 积石山| 新宾| 永登县| 双流县| 兴义市| 扶余县| 龙门县| 双城市| 平昌县| 乌拉特后旗| 曲阳县| 平阴县| 上犹县| 剑川县| 盐山县| 延吉市| 宜章县| 桃园市| 洪雅县| 六盘水市| 商南县| 济宁市| 东辽县| 长沙市| 中江县| 尉氏县| 德安县| 平潭县|