1. 程式人生 > >c++11 中的注意事項

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> class
People { 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通過
}