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

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

C++箴言:了解C++偷偷加上和調(diào)用了什么

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

  幾乎每一個你自己寫的類都會有一個或多個構(gòu)造函數(shù),一個析構(gòu)函數(shù)和一個拷貝賦值運(yùn)算符。不要驚異,那是些就像你的面包黃油一樣的函數(shù),他們控制著基本的操作,如創(chuàng)建一個新的對象并確保已被初始化,消除一個函數(shù)并確保它被完全清除,以及為對象賦予一個新值。這些函數(shù)中出現(xiàn)錯誤,將引起你的類出現(xiàn)影響深遠(yuǎn)的,而且令人不快的反彈,所以保證他們正確是生死攸關(guān)的事情。本章中,我將對如何組裝這些函數(shù)以成為一個好的類的中樞骨干提供一些指導(dǎo)。

  什么時候一個空的類將變得不空?答案是當(dāng) C++ 得到了它。假如你自己不聲明一個拷貝構(gòu)造函數(shù),一個拷貝賦值運(yùn)算符和一個析構(gòu)函數(shù),編譯器就會為這些東西聲明一個它自己的版本。而且,假如你自己連一個構(gòu)造函數(shù)都沒有聲明,編譯器就會為你聲明一個缺省構(gòu)造函數(shù)。所有這些函數(shù)都被聲明為 public 和 inline(參見 Item 30)。作為結(jié)果,假如你寫

class Empty{};
  在本質(zhì)上和你如下寫是一樣的:

class Empty {
 public:
  Empty() { ... } // default constrUCtor
  Empty(const Empty& rhs) { ... } // copy constructor
  ~Empty() { ... } // destructor - see below
  // for whether it’s virtual
  Empty& Operator=(const Empty& rhs) { ... } // copy assignment operator
};
  這些函數(shù)只有在它們被需要的時候才會生成,但是并不需要做太多的事情,就會用到它們。下面的代碼會促使每一個函數(shù)生成:

Empty e1; // default constructor;
// destructor

Empty e2(e1); // copy constructor

e2 = e1; // copy assignment operator
  假設(shè)編譯器為你寫成了這些函數(shù),那么它們做些什么呢?缺省構(gòu)造函數(shù)和析構(gòu)函數(shù)主要是給編譯器一個地方放置“幕后的”諸如調(diào)用基類和 non-static 數(shù)據(jù)成員的構(gòu)造函數(shù)和析構(gòu)函數(shù)的代碼。注重,生成的析構(gòu)函數(shù)是非虛擬(non-virtual)的,除非它從一個基類繼續(xù)而來,而基類聲明了一個虛析構(gòu)函數(shù)(這種情況下,函數(shù)的虛擬性來自基類)。

  編譯器版本的拷貝構(gòu)造函數(shù)和拷貝賦值運(yùn)算符,只是簡單地從原對象拷貝每一個 non-static 數(shù)據(jù)成員到目標(biāo)對象。例如,考慮一個將名字和類型為 T 的對象聯(lián)系起來的 NamedObject 模板

template<typename T>
class NamedObject {
 public:
  NamedObject(const char *name, const T& value);
  NamedObject(const std::string& name, const T& value);
  ..
 PRivate:
  std::string nameValue;
  T objectValue;
};
  因為 NamedObject 中聲明了構(gòu)造函數(shù),編譯器就不會再生成缺省構(gòu)造函數(shù)。這一點非常重要,它意味著假如你足夠謹(jǐn)慎地設(shè)計你的類,使它需要構(gòu)造函數(shù)參數(shù),你就不必顧慮編譯器會不顧你的決定,輕率地增加一個不需要參數(shù)的構(gòu)造函數(shù)。

  NamedObject 既沒有聲明拷貝構(gòu)造函數(shù)也沒有聲明拷貝賦值運(yùn)算符,所以編譯器將生成這些函數(shù)(當(dāng)然是在需要的時候)??矗@就是拷貝構(gòu)造函數(shù)的用法:

NamedObject<int> no1("Smallest Prime Number", 2);
NamedObject<int> no2(no1); // calls copy constructor
  編譯器生成的拷貝構(gòu)造函數(shù)一定會用 no1.nameValue 和 no1.objectValue 分別初始化 no2.nameValue 和 no2.objectValue。nameValue 的類型是 string,標(biāo)準(zhǔn) string 類型有一個拷貝構(gòu)造函數(shù),所以將以 no1.nameValue 作為參數(shù)調(diào)用 string 的拷貝構(gòu)造函數(shù)初始化 no2.nameValue。而另一方面,NamedObject<int>::objectValue 的類型是 int(因為在這個模板的實例化中 T 是 int),而 int 是內(nèi)建類型,所以 no2.objectValue 將通過拷貝no1.objectValue 的每一個位來初始化。

  編譯器為 NamedObject<int> 生成的拷貝賦值運(yùn)算符本質(zhì)上也會有同樣的行為,但是,通常情況下,只有在結(jié)果代碼合法而且有一個合理的可理解的邏輯時,編譯器生成的拷貝賦值運(yùn)算符才會有我所描述的行為方式。假如這兩項檢測中的任一項失敗了,編譯器將拒絕為你的類生成一個 operator=。

  例如,假設(shè) NamedObject 如下定義,nameValue 是一個 string 的引用,而 objectValue 是一個 const T:

template<class T>

class NamedObject {
 public:
  // this ctor no longer takes a const name, because nameValue
  // is now a reference-to-non-const string. The char* constructor
  // is gone, because we must have a string to refer to.

  NamedObject(std::string& name, const T& value);
  ... // as above, assume no
  // operator= is declared
 private:
  std::string& nameValue; // this is now a reference
  const T objectValue; // this is now const
};
  現(xiàn)在,考慮這里會發(fā)生什么:


std::string newDog("Persephone");
std::string oldDog("Satch");

NamedObject<int> p(newDog, 2); // when I originally wrote this, our
// dog Persephone was about to
// have her second birthday
NamedObject<int> s(oldDog, 36); // the family dog Satch (from my
// childhood) would be 36 if she
// were still alive

p = s; // what should happen to
// the data members in p?
  賦值之前,p.nameValue 和 s.nameValue 都引向 string 對象,但并非同一個。那個賦值對 p.nameValue 產(chǎn)生了什么影響呢?賦值之后,p.nameValue 所引向的字符串是否就是 s.nameValue 所引向的那一個呢,也就是說,引用本身被改變了?假如是這樣,就違反了常規(guī),因為 C++ 并沒有提供使一個引用引向另一個對象的方法。換一種思路,是不是 p.nameValue 所引向的那個 string 對象被改變了,從而保持指針或引用還是指向那個對象,也就是說,賦值并沒有直接影響對象?這是編譯器產(chǎn)生的拷貝賦值運(yùn)算符應(yīng)該做的事情嗎?

  面對這個難題,C++ 拒絕編譯器產(chǎn)生代碼。假如你希望一個包含引用成員的類支持賦值,你必須自己定義拷貝賦值運(yùn)算符。面對含有 const 成員的類時,編譯器也會如此行事(就象上面那個改變后的類中的 objectValue)。改變 const 成員是不合法的,所以編譯器隱式產(chǎn)生的賦值函數(shù)無法確定該如何對待它們。最后,假如基類將拷貝賦值運(yùn)算符聲明為 private,編譯器拒絕為其派生類產(chǎn)生隱式的拷貝賦值運(yùn)算符。究竟,編譯器為派生類產(chǎn)生的拷貝賦值運(yùn)算符也要處理其基類部分,但假如這樣做,它們當(dāng)然無法調(diào)用那些派生類無權(quán)調(diào)用的成員函數(shù)。

  Things to Remember

  編譯器可以隱式產(chǎn)生一個類的缺省構(gòu)造函數(shù),拷貝構(gòu)造函數(shù),拷貝賦值運(yùn)算符和析構(gòu)函數(shù)。

發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 崇阳县| 松原市| 师宗县| 阳春市| 钟山县| 抚远县| 淳化县| 饶平县| 威信县| 绿春县| 井研县| 平昌县| 漯河市| 东乌珠穆沁旗| 林西县| 台中县| 岗巴县| 赞皇县| 昌宁县| 太原市| 张家界市| 仙居县| 许昌市| 屯昌县| 昭苏县| 鄂托克旗| 津市市| 延津县| 汾阳市| 区。| 凌云县| 宁津县| 永和县| 瑞丽市| 洛浦县| 洮南市| 乌恰县| 吉隆县| 宜州市| 定陶县| 花垣县|