c++11 中的註意事項
1. C++11標準中讓類的析構函數默認也是noexcept(true)的。 但如果顯式地為析構函數指定了noexcept,或者類的基類或成員有noexcept(false)的析構函數,析構函數就不會再保持默認值。
2. 初始化成員變量:
c++98中,支持在類聲明中使用等號“=”進行初始化,但要求必須為靜態成員常量,而且也只能是整形或枚舉類型才能初始化。
而在c++11中,允許使用等號或花括號進行非靜態成員變量的初始化,比如:
struct init{ int a = 1; double b {1.2}; }
上述代碼中,給非靜態成員a和b分別賦予初值1和1.2.
若同時使用就地初始化和初始化列表兩種方式,結果是初始化列表後作用於非靜態成員,即最終所賦值的是初始化列表中的值。
3. 擴展的friend語法:
class Poly; typedef Poly P; class LiLei { friend class Poly; // c++98通過,c++11通過 }; class Jim { friend Poly; //c++98失敗,c++11通過 }; class HanMeiMei { friend P; //c++98失敗,c++11通過 };
c++11在聲明一個類為另一個類友元時,不再需要使用class關鍵字,或者使用別名。
這樣可以為類模板聲明友元:
class P; template <typename T> classPeople { friend T; }; People<P> PP; //類型P在這裏是People類型的友元 People<int> Pi; //對於int類型模板參數,友元聲明被忽略
4. c++11中阻止一個函數在派生類中被重載,使用final:
class Object { virtual void fun() = 0; }; class Base: public Object { void fun() final; }; class Derived: public Base { void fun(); //無法通過編譯 };
在類Base中將函數fun()聲明為final,那麽派生於Base的Derived類則不能重載fun()。
若在派生類中在虛函數聲明時使用override,表明該函數必須重載其基類中能的同名函數:
class Base { virtual void Turing() = 0; virtual void Dijkstra() = 0; virtual void VNeumann(int g) = 0; void print(); }; class Derived: public Base { void Turing() override; void Dikjstra() override; //無法通過編譯,拼寫錯誤 void VNeumann(double g); //無法通過編譯,參數不一致 void print() override; //無法通過編譯,非虛函數重載 };
若沒有override修飾符,則Derived則會通過編譯,但並沒有實現想要重載的功能。
5. 模板函數的默認模板參數
在c++98中函數模板不能有默認參數,而在c++11中則可以有:
void DefParm(int m = 3) {} //c++98通過編譯,c++11通過編譯 template <typename T = int> class DefClass {}; //c++98通過編譯,c++11通過編譯 template <typename T = int> void DefTempParm() {}; //c++98編譯失敗,c++11通過編譯
對於類模板來說,默認模板參數聲明指定默認值時,需要按照從右往左的規則進行指定,而對於函數模板則不是必須的。
template <typename T1, typename T2 = int> class DefClass1; template <typename T1 = int, typename T2> class DefClass2; //無法通過編譯 template <typename T, int i = 0> class DefClass3; template <int i = 0, typename T> class DefClass4; //無法通過編譯 template <typename T1 = int, typename = T2> void DefFunc1(T1 a, T2 b); template <int i = 0, typename T> void DefFunc2(T a);
6. 外部模板
編譯時,對於源代碼中出現的每一處模板實例化,編譯器都需要去做實例化的通過;而在鏈接時,鏈接器還需要移除重復的實例化代碼。解決該問題的方法是使用外部模板。c++98中已有的一個特性是顯式實例化:
template <typename T> void fun(T) {} 聲明: template void fun<int>(int);
在c++11中,外部模板的聲明為:
extern template void fun<int>(int);
7. 局部和匿名類型作為模板實參
template <tyypename T> class X {}; template <typename T> void TempFun(T t) {} struct A {} a; struct { int i; } b; //匿名類型變量 typedef struct { int i; } B; //匿名類型 void Fun() { struct C {} c; //局部類型 X<A> x1; //c++98通過,c++11通過 X<B> x2; //c++98不通過,c++11通過 X<C> x3; //c++98不通過,c++11通過 TempFun(a); //c++98通過,c++11通過 TempFun(b); //c++98不通過,c++11通過 TempFun(c); //c++98不通過,c++11通過 }
c++11 中的註意事項