C++11語法甜點2

語法甜點11:非成員的begin和end
    在C++ 03中,標準容器都提供了begin和end成員函數,但對於普通數組,則只能使用不同的寫法。比如:
1 vector<int> v; 
2 int a[100]; 
3 sort(v.begin(), v.end()); 
4 sort(a, a+sizeof(a)/sizeof(a[0]));
    爲了統一語法,C++ 11提供了非成員的begin和end函數。用法如下:
1 sort(begin(v), end(v)); 
2 sort(begin(a), end(a));
   
    語法甜點12:顯式虛函數重載   
    在引入C++ 11之前,基類和派生類中的虛函數很容易產生錯誤使用的情況。比如:
    a、基類添加了一個虛函數,但該虛函數與派生類中的某個已有普通函數相同。
    b、派生類添加了一個普通函數,但該函數與基類中的某個已有虛函數相同。
    爲了避免這些情況,在C++ 11中可以使用override來顯式地表明需要進行虛函數重載。比如:
複製代碼
 1 class Base 
 2 {
 3     virtual void some_func(float);
 4 };
 5 
 6 class Derived : public Base
 7  {
 8     virtual void some_func(int) override;        // 將產生編譯錯誤
 9    virtual void some_func(float) override;    // 正確
10 };
複製代碼
    注意:爲了保持向後兼容,此功能是選擇性的。
    C++ 11中還引入了final指示符,用於防止類或接口被繼承。比如:
複製代碼
 1 class  Base1 final { };
 2 class Derived1 : public Base1 { };            // 將產生編譯錯誤
 3 class Base2
 4 {
 5     virtual void f() final;
 6 };
 7 class Derived2 : public Base2
 8 {
 9     void f();                                             // 將產生編譯錯誤
10 };
複製代碼
   
    語法甜點13:強類型枚舉
    在C++ 03中,枚舉類型不是類型安全的。枚舉類型被視爲整數,這使得兩種不同的枚舉類型之間可以進行比較。C++ 03唯一提供的安全機制就是一個整數或一個枚舉型值不能隱式轉換爲另一個枚舉型值。
    在C++ 11中,引入了enum class來聲明類型安全的枚舉類型。比如:
enum class IColor1 { Red, Blue, Gree=100, Black };
    IColor1不能隱式地轉換爲整數類型,也不能與整數類型比較大小。使用枚舉名時,必須明確指定其所屬範圍,比如:必須使用IColor1::Red,而不能單獨使用Red。
    在C++ 11中,使用enum class和傳統的enum時,還可以指定其所用的數據類型,不指定時默認爲int。比如:
1 enum class IColor2 : unsigned int { Red, Blue, Gree=100, Black };
2 enum IColor3 : unsigned int { Red, Blue, Gree=100, Black };
    另外,在C++ 03中,無法對枚舉類型進行前置聲明。而在C++ 11中,只要是使用了指定數據類型的新式枚舉,都可以進行前置聲明。比如:
1 enum class IColor1;
2 enum class IColor2 : unsigned int;
3 enum IColor3 : unsigned int;
   
    語法甜點14:模板別名
    在C++ 03中,可以使用typedef給模板類指定一個新的類型名稱,但卻不能給類模板指定別名。比如:
1 template< typename first, typename second, int third>
2 class SomeType;   template< typename second>
3 typedef SomeType<OtherType, second, 5> TypedefName;  // 在C++ 03中是不合法的
    爲了能夠定義類模板的別名,C++ 11允許像下面這樣使用using關鍵字:
1 template< typename first, typename second, int third>
2 class SomeType;
3 template< typename second>
4 using TypedefName = SomeType<OtherType, second, 5>;
    另外,using也能定義一般類型的別名,此時等同於typedef。比如:
1 typedef void (*Func)(int);
2 using  Func = void (*)(int);
    
    語法甜點15:無限制的union
    在C++ 03中,並非任意的數據類型都能做爲union的成員。比方說,帶有non-trivial構造函數的類型就不能是 union 的成員。在C++ 11中,移除了所有對union的使用限制,除了其成員仍然不能是引用類型這種情況。 
複製代碼
 1 struct point
 2 {
 3      point() {}
 4      point(int x, int y): m_x(x), m_y(y) {}
 5      int m_x, m_y;
 6 };
 7 union
 8 {
 9      int z;
10      double w;
11      point p;                     // 在C++ 03中不合法;在C++ 11中合法
12 };
複製代碼
    備註:C++ 03中不適合做union成員變量的情形有以下幾種:
        1、類或結構體中含有non-trival的構造函數(拷貝構造函數)、析構函數、拷貝賦值操作符、虛函數等。
        2、類的基類和成員變量中含有1中所述幾個函數。
        3、靜態變量。
        4、變量引用。
 
    語法甜點16:新的字符串字面值
    C++ 03提供了兩種字符串字面值。第一種,包含有雙引號,產生以空字符結尾的const char數組。第二種,有着前標L,產生以空字符結尾的const wchar_t數組,其中wchar_t代表寬字符。C++ 03不支持Unicode編碼。
    在C++ 11中,爲了加強C++編譯器對Unicode的支持,類別char的定義被修改爲其大小至少能夠存儲UTF-8的8位編碼,並且能夠容納編譯器的基本字符集的任何成員。
    C++ 11 支持三種Unicode編碼方式:UTF-8,UTF-16,和UTF-32。除了上述char定義的變更, C++ 11還增加了兩種新的字符類別:char16_t和char32_t,用於存儲UTF-16和UTF-32的字符。
    下面展示瞭如何產生使用這些編碼的字符串字面值:
1 u8"I'm a UTF-8 string."
2 u"This is a UTF-16 string."
3 U"This is a UTF-32 string."
    第一個字符串的類型是通常的const char[],第二個字符串的類型是const char16_t[],第三個字符串的類型是const char32_t[]。 
    爲了避免在字符串中頻繁使用轉義字符的麻煩,C++11還提供了raw字符串字面值。比如:
1 R"(The String Data \ Stuff " )"
2 R"delimiter(The String Data \ Stuff " )delimiter"
    raw字符串字面值能夠和寬字面值或Unicode字面值結合起來使用,比如:
1 u8R"XXX(I'm a "raw UTF-8" string.)XXX"
2 uR"*@(This is a "raw UTF-16" string.)*@"
3 UR"(This is a "raw UTF-32" string.)"
    
    語法甜點17:sizeof
    在C++ 11中,允許sizeof運算符作用在類型的數據成員上,而無須明確的對象。在C++ 03中,這是不允許的,會導致編譯錯誤。比如:
1 struct SomeType { OtherType member; };
2 sizeof(SomeType::member);        // 在C++ 03中不合法;在C++ 11中合法
 
    語法甜點18:新的算法
    C++ 11中新增了一些比較實用的算法。比如all_of、any_of、none_of、copy_n、copy_if和iota等。參考代碼如下:
複製代碼
1 int a[5] = {-2, -1, 0, 1, 2};
2 auto funIsPositive = [](int v){return v>0;};
3 bool bRet = all_of(a, a+5, funIsPositive);             // false
4 bRet = any_of(a, a+5, funIsPositive);                  // true
5 bRet = none_of(a, a+5, funIsPositive);                // false
6 int b[5] = {0};
7 copy_n(a, 5, b);                                                // 將a開始的5個元素拷貝到b中
8 copy_if(a, a+5, b, funIsPositive);                        // 將1, 2兩個數拷貝到b中
9 iota(a, a+5, 10);                                               // a中的每個元素加10
複製代碼
    
    語法甜點19:泛化的常數表達式
    C++ 03中本來就已經具有常數表示式的概念,比如:3+5,6*7等。常數表示式對編譯器來說是優化的機會,編譯器常在編譯期運行它們並且將值存入程序中。同樣地,在許多場合下,C++規範要求使用常數表示式。比如數組大小、枚舉值等。
    然而,常數表示式總是在遇到了函數調用時就終結。比如:
1 int GetFive() { return 5; }
2 int some_value[GetFive() + 5];         // 不合法
    C++ 11引進關鍵字constexpr允許用戶保證函數是編譯期常數。比如:
1 constexpr int GetFive() { return 5; }
2 int some_value[GetFive() + 5];
    
    語法甜點20:包裝引用
    包裝引用類似於一般的引用。對於任意對象,我們可以通過模板類ref得到一個包裝引用 (至於常引用,則可以通過 cref 得到)。考慮下面的代碼:
複製代碼
1 void f (int &r)  { r++; }
2 template<class F, class P> void g (F f, P t)  { f(t); }
3 
4 int n = 0 ;
5 g(f, n) ;
6 cout << n << endl;                     // 輸出0
7 g(f, ref(n));
8 cout << n << endl;                     // 輸出1
複製代碼

 


  語法甜點11:非成員的begin和end
    在C++ 03中,標準容器都提供了begin和end成員函數,但對於普通數組,則只能使用不同的寫法。比如:

1 vector<int> v; 
2 int a[100]; 
3 sort(v.begin(), v.end()); 
4 sort(a, a+sizeof(a)/sizeof(a[0]));
    爲了統一語法,C++ 11提供了非成員的begin和end函數。用法如下:
1 sort(begin(v), end(v)); 
2 sort(begin(a), end(a));
   
    語法甜點12:顯式虛函數重載   
    在引入C++ 11之前,基類和派生類中的虛函數很容易產生錯誤使用的情況。比如:
    a、基類添加了一個虛函數,但該虛函數與派生類中的某個已有普通函數相同。
    b、派生類添加了一個普通函數,但該函數與基類中的某個已有虛函數相同。
    爲了避免這些情況,在C++ 11中可以使用override來顯式地表明需要進行虛函數重載。比如:
複製代碼
 1 class Base 
 2 {
 3     virtual void some_func(float);
 4 };
 5 
 6 class Derived : public Base
 7  {
 8     virtual void some_func(int) override;        // 將產生編譯錯誤
 9    virtual void some_func(float) override;    // 正確
10 };
複製代碼
    注意:爲了保持向後兼容,此功能是選擇性的。
    C++ 11中還引入了final指示符,用於防止類或接口被繼承。比如:
複製代碼
 1 class  Base1 final { };
 2 class Derived1 : public Base1 { };            // 將產生編譯錯誤
 3 class Base2
 4 {
 5     virtual void f() final;
 6 };
 7 class Derived2 : public Base2
 8 {
 9     void f();                                             // 將產生編譯錯誤
10 };
複製代碼
   
    語法甜點13:強類型枚舉
    在C++ 03中,枚舉類型不是類型安全的。枚舉類型被視爲整數,這使得兩種不同的枚舉類型之間可以進行比較。C++ 03唯一提供的安全機制就是一個整數或一個枚舉型值不能隱式轉換爲另一個枚舉型值。
    在C++ 11中,引入了enum class來聲明類型安全的枚舉類型。比如:
enum class IColor1 { Red, Blue, Gree=100, Black };
    IColor1不能隱式地轉換爲整數類型,也不能與整數類型比較大小。使用枚舉名時,必須明確指定其所屬範圍,比如:必須使用IColor1::Red,而不能單獨使用Red。
    在C++ 11中,使用enum class和傳統的enum時,還可以指定其所用的數據類型,不指定時默認爲int。比如:
1 enum class IColor2 : unsigned int { Red, Blue, Gree=100, Black };
2 enum IColor3 : unsigned int { Red, Blue, Gree=100, Black };
    另外,在C++ 03中,無法對枚舉類型進行前置聲明。而在C++ 11中,只要是使用了指定數據類型的新式枚舉,都可以進行前置聲明。比如:
1 enum class IColor1;
2 enum class IColor2 : unsigned int;
3 enum IColor3 : unsigned int;
   
    語法甜點14:模板別名
    在C++ 03中,可以使用typedef給模板類指定一個新的類型名稱,但卻不能給類模板指定別名。比如:
1 template< typename first, typename second, int third>
2 class SomeType;   template< typename second>
3 typedef SomeType<OtherType, second, 5> TypedefName;  // 在C++ 03中是不合法的
    爲了能夠定義類模板的別名,C++ 11允許像下面這樣使用using關鍵字:
1 template< typename first, typename second, int third>
2 class SomeType;
3 template< typename second>
4 using TypedefName = SomeType<OtherType, second, 5>;
    另外,using也能定義一般類型的別名,此時等同於typedef。比如:
1 typedef void (*Func)(int);
2 using  Func = void (*)(int);
    
    語法甜點15:無限制的union
    在C++ 03中,並非任意的數據類型都能做爲union的成員。比方說,帶有non-trivial構造函數的類型就不能是 union 的成員。在C++ 11中,移除了所有對union的使用限制,除了其成員仍然不能是引用類型這種情況。 
複製代碼
 1 struct point
 2 {
 3      point() {}
 4      point(int x, int y): m_x(x), m_y(y) {}
 5      int m_x, m_y;
 6 };
 7 union
 8 {
 9      int z;
10      double w;
11      point p;                     // 在C++ 03中不合法;在C++ 11中合法
12 };
複製代碼
    備註:C++ 03中不適合做union成員變量的情形有以下幾種:
        1、類或結構體中含有non-trival的構造函數(拷貝構造函數)、析構函數、拷貝賦值操作符、虛函數等。
        2、類的基類和成員變量中含有1中所述幾個函數。
        3、靜態變量。
        4、變量引用。
 
    語法甜點16:新的字符串字面值
    C++ 03提供了兩種字符串字面值。第一種,包含有雙引號,產生以空字符結尾的const char數組。第二種,有着前標L,產生以空字符結尾的const wchar_t數組,其中wchar_t代表寬字符。C++ 03不支持Unicode編碼。
    在C++ 11中,爲了加強C++編譯器對Unicode的支持,類別char的定義被修改爲其大小至少能夠存儲UTF-8的8位編碼,並且能夠容納編譯器的基本字符集的任何成員。
    C++ 11 支持三種Unicode編碼方式:UTF-8,UTF-16,和UTF-32。除了上述char定義的變更, C++ 11還增加了兩種新的字符類別:char16_t和char32_t,用於存儲UTF-16和UTF-32的字符。
    下面展示瞭如何產生使用這些編碼的字符串字面值:
1 u8"I'm a UTF-8 string."
2 u"This is a UTF-16 string."
3 U"This is a UTF-32 string."
    第一個字符串的類型是通常的const char[],第二個字符串的類型是const char16_t[],第三個字符串的類型是const char32_t[]。 
    爲了避免在字符串中頻繁使用轉義字符的麻煩,C++11還提供了raw字符串字面值。比如:
1 R"(The String Data \ Stuff " )"
2 R"delimiter(The String Data \ Stuff " )delimiter"
    raw字符串字面值能夠和寬字面值或Unicode字面值結合起來使用,比如:
1 u8R"XXX(I'm a "raw UTF-8" string.)XXX"
2 uR"*@(This is a "raw UTF-16" string.)*@"
3 UR"(This is a "raw UTF-32" string.)"
    
    語法甜點17:sizeof
    在C++ 11中,允許sizeof運算符作用在類型的數據成員上,而無須明確的對象。在C++ 03中,這是不允許的,會導致編譯錯誤。比如:
1 struct SomeType { OtherType member; };
2 sizeof(SomeType::member);        // 在C++ 03中不合法;在C++ 11中合法
 
    語法甜點18:新的算法
    C++ 11中新增了一些比較實用的算法。比如all_of、any_of、none_of、copy_n、copy_if和iota等。參考代碼如下:
複製代碼
1 int a[5] = {-2, -1, 0, 1, 2};
2 auto funIsPositive = [](int v){return v>0;};
3 bool bRet = all_of(a, a+5, funIsPositive);             // false
4 bRet = any_of(a, a+5, funIsPositive);                  // true
5 bRet = none_of(a, a+5, funIsPositive);                // false
6 int b[5] = {0};
7 copy_n(a, 5, b);                                                // 將a開始的5個元素拷貝到b中
8 copy_if(a, a+5, b, funIsPositive);                        // 將1, 2兩個數拷貝到b中
9 iota(a, a+5, 10);                                               // a中的每個元素加10
複製代碼
    
    語法甜點19:泛化的常數表達式
    C++ 03中本來就已經具有常數表示式的概念,比如:3+5,6*7等。常數表示式對編譯器來說是優化的機會,編譯器常在編譯期運行它們並且將值存入程序中。同樣地,在許多場合下,C++規範要求使用常數表示式。比如數組大小、枚舉值等。
    然而,常數表示式總是在遇到了函數調用時就終結。比如:
1 int GetFive() { return 5; }
2 int some_value[GetFive() + 5];         // 不合法
    C++ 11引進關鍵字constexpr允許用戶保證函數是編譯期常數。比如:
1 constexpr int GetFive() { return 5; }
2 int some_value[GetFive() + 5];
    
    語法甜點20:包裝引用
    包裝引用類似於一般的引用。對於任意對象,我們可以通過模板類ref得到一個包裝引用 (至於常引用,則可以通過 cref 得到)。考慮下面的代碼:
複製代碼
1 void f (int &r)  { r++; }
2 template<class F, class P> void g (F f, P t)  { f(t); }
3 
4 int n = 0 ;
5 g(f, n) ;
6 cout << n << endl;                     // 輸出0
7 g(f, ref(n));
8 cout << n << endl;                     // 輸出1
複製代碼

 


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章