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

c++11 中的註意事項

函數聲明 style 枚舉類型 clas 關鍵字 def 解決 c++ 還需

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通過
}

c++11 中的註意事項