轉(zhuǎn)帖|行業(yè)資訊|編輯:龔雪|2016-04-26 09:15:59.000|閱讀 351 次
概述:本文主要為大家介紹C++ 11中對類新增的特性,歡迎品鑒!
# 界面/圖表報表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
在我們沒有顯式定義類的復(fù)制構(gòu)造函數(shù)和賦值操作符的情況下,編譯器會為我們生成默認(rèn)的這兩個函數(shù):默認(rèn)的賦值函數(shù)以內(nèi)存復(fù)制的形式完成對象的復(fù)制。
這種機制可以為我們節(jié)省很多編寫復(fù)制構(gòu)造函數(shù)和賦值操作符的時間,但是在某些情況下,比如我們不希望對象被復(fù)制,在之前我們需要將復(fù)制構(gòu)造函數(shù)和賦值操作符聲明為private,現(xiàn)在可以使用delete關(guān)鍵字實現(xiàn):
class X { // … X& operator=(const X&) = delete; // 禁用類的賦值操作符 X(const X&) = delete; };
顯式地使用default關(guān)鍵字聲明使用類的默認(rèn)行為,對于編譯器來說明顯是多余的,但是對于代碼的閱讀者來說,使用default顯式地定義復(fù)制操作,則意味著這個復(fù)制操作就是一個普通的默認(rèn)的復(fù)制操作。
派生類中可以不實現(xiàn)基類虛函數(shù),也可以實現(xiàn),但不使用virtual關(guān)鍵字;這很容易給人造成混淆,有時為了確認(rèn)某個函數(shù)是否是虛函數(shù),我們不得不追溯到基類查看;C++11引入了兩個新的標(biāo)識符: override和final。override,表示函數(shù)應(yīng)當(dāng)重寫基類中的虛函數(shù)。(用于派生類的虛函數(shù)中)final,表示派生類不應(yīng)當(dāng)重寫這個虛函數(shù)。(用于基類中)
struct B { virtual void f(); virtual void g() const; virtual void h(char); void k(); // non-virtual virtual void m() final; }; struct D : B { void f() override; // OK: 重寫 B::f() void g() override; // error: 不同的函數(shù)聲明,不能重寫 virtual void h(char); // 重寫 B::h( char ); 可能會有警告 void k() override; // error: B::k() 不是虛函數(shù) virtual void m(); // error: m()在基類中聲明禁止重寫 };
有了它們虛函數(shù)用起來更為安全,也更好閱讀。
在C++98中,如果你想讓兩個構(gòu)造函數(shù)完成相似的事情,可以寫兩個大段代碼相同的構(gòu)造函數(shù),或者是另外定義一個init()函數(shù),讓兩個構(gòu)造函數(shù)都調(diào)用這個init()函數(shù)。例如:
class X { int a; // 實現(xiàn)一個初始化函數(shù) validate(int x) { if (0<x && x<=max) a=x; else throw bad_X(x); } public: // 三個構(gòu)造函數(shù)都調(diào)用validate(),完成初始化工作 X(int x) { validate(x); } X() { validate(42); } X(string s) { int x = lexical_cast<int>(s); validate(x); } // … };
這樣的實現(xiàn)方式重復(fù)羅嗦,并且容易出錯。
在C++0x中,我們可以在定義一個構(gòu)造函數(shù)時調(diào)用另外一個構(gòu)造函數(shù):
class X { int a; public: X(int x) { if (0<x && x<=max) a=x; else throw bad_X(x); } // 構(gòu)造函數(shù)X()調(diào)用構(gòu)造函數(shù)X(int x) X() :X{42} { } // 構(gòu)造函數(shù)X(string s)調(diào)用構(gòu)造函數(shù)X(int x) X(string s) :X{lexical_cast<int>(s)} { } // … };
C++11提供了將構(gòu)造函數(shù)晉級的能力:比如以下這個示例,基類提供一個帶參數(shù)的構(gòu)造函數(shù),而派生類沒有提供;如果直接使用D1 d(6);將會報錯;通過將基類構(gòu)造函數(shù)晉級,派生類中會隱式聲明構(gòu)造函數(shù)D1(int);需要注意的是,晉級后的基類構(gòu)造函數(shù)是無法初始化派生類的成員變量的,所以如果派生類中有成員變量,需要使用初始化列表初始化;
struct B1 { B1(int) { } }; struct D1 : B1 { using B1::B1; // 隱式聲明構(gòu)造函數(shù)D1(int) // 注意:在聲明的時候x變量已經(jīng)被初始化 int x{0}; }; void test() { D1 d(6); // d.x的值是0 }
在C++98標(biāo)準(zhǔn)里,只有static const聲明的整型成員能在類內(nèi)部初始化,并且初始化值必須是常量表達(dá)式。這些限制確保了初始化操作可以在編譯時期進行。
class X { static const int m1 = 7; // 正確 const int m2 = 7; // 錯誤:無static static int m3 = 7; // 錯誤:無const static const string m5 = “odd”; //錯誤:非整型 };
C++11的基本思想是,允許非靜態(tài)(non-static)數(shù)據(jù)成員在其聲明處(在其所屬類內(nèi)部)進行初始化。這樣,在運行時,需要初始值時構(gòu)造函數(shù)可以使用這個初始值。現(xiàn)在,我們可以這么寫:
class A { public: int a = 7; }; 它等同于使用初始化列表: class A { public: int a; A() : a(7) {} };
單純從代碼來看,這樣只是省去了一些文字輸入,但在有多個構(gòu)造函數(shù)的類中,其好處就很明顯了:
class A { public: A(): a(7), b(5), hash_algorithm(“MD5″), s(“Constructor run”) {} A(int a_val) : a(a_val), b(5), hash_algorithm(“MD5″), s(“Constructor run”) {} A(D d) : a(7), b(g(d)), hash_algorithm(“MD5″), s(“Constructor run”) {} int a, b; private: // 哈希加密函數(shù)可應(yīng)用于類A的所有實例 HashingFunction hash_algorithm; std::string s; // 用以指明對象正處于生命周期內(nèi)何種狀態(tài)的字符串 };
可以簡化為:
class A { public: A() {} A(int a_val) : a(a_val) {} A(D d) : b(g(d)) {} int a = 7; int b = 5; private: //哈希加密函數(shù)可應(yīng)用于類A的所有實例 HashingFunction hash_algorithm{“MD5″}; //用以指明對象正處于生命周期內(nèi)何種狀態(tài)的字符串 std::string s{“Constructor run”};
在C++98中,我們自定義的類,會默認(rèn)生成拷貝賦值操作符函數(shù)和拷貝賦值函數(shù)以及析構(gòu)函數(shù);在C++11中,依賴于新增的move語義,默認(rèn)生成的函數(shù)多了2個移動相關(guān)的:移動賦值操作符( move assignment )和移動構(gòu)造函數(shù)( move constructor );BS建議,如果你顯式聲明了上述 5 個函數(shù)或操作符中的任何一個,你必須考慮其余的 4 個,并且顯式地定義你需要的操作,或者使用這個操作的默認(rèn)行為。
一旦我們顯式地指明( 聲明 , 定義 , =default , 或者 =delete )了上述五個函數(shù)之中的任意一個,編譯器將不會默認(rèn)自動生成move操作。一旦我們顯式地指明( 聲明 , 定義 , =default , 或者 =delete )了上述五個函數(shù)之中的任意一個,編譯器將默認(rèn)自動生成所有的拷貝操作。但是,我們應(yīng)該盡量避免這種情況的發(fā)生,不要依賴于編譯器的默認(rèn)動作。
如果你聲明了上述 5 個默認(rèn)函數(shù)中的任何一個,強烈建議你顯式地聲明所有這 5 個默認(rèn)函數(shù)。例如:
template<class T> class Handle { T* p; public: Handle(T* pp) : p{pp} {} // 用戶定義構(gòu)造函數(shù): 沒有隱式的拷貝和移動操作 ~Handle() { delete p; } Handle(Handle&& h) :p{h.p} { h.p=nullptr; }; // transfer ownership Handle& operator=(Handle&& h) { delete p; p=h.p; h.p=nullptr; } // 傳遞所有權(quán) Handle(const Handle&) = delete; // 禁用拷貝構(gòu)造函數(shù) Handle& operator=(const Handle&) = delete; // ... };
本站文章除注明轉(zhuǎn)載外,均為本站原創(chuàng)或翻譯。歡迎任何形式的轉(zhuǎn)載,但請務(wù)必注明出處、不得修改原文相關(guān)鏈接,如果存在內(nèi)容上的異議請郵件反饋至chenjj@fc6vip.cn
文章轉(zhuǎn)載自:慧都控件網(wǎng)