1. 程式人生 > >C++11--20分鐘瞭解C++11 (上)

C++11--20分鐘瞭解C++11 (上)

20分鐘瞭解C++ 11

1 初始化列表 Initializer List


//C++ 03中用初始化列表初始化陣列
int arr[4] = {3, 2, 4, 5};

vector<int> v;
v.push_back(3);
v.push_back(2);
v.push_back(4);
v.push_back(5);



// C++ 11 做了擴充套件,可以初始化vector
vector<int> v = {3, 4, 1, 9};   // 呼叫初始化列表建構函式
// 所以相關的STL容器都更新了,支援初始化列表



// 定義自己的初始化列表建構函式:
#include <initializer_list>
class BoVector {
   vector<int> m_vec;
   public:
   BoVector(const initializer_list<int>& v) {
      for (initializer_list<int>::iterator itr = v.begin(); itr!=v.end(); ++ itr)
         m_vec.push_back(*itr);
   }
};

BoVector v = {0, 2, 3, 4};
BoVector v{0, 2, 3, 4};   // 初始化的另一種方式


// 自動進行常規的初始化
class Rectangle {
   public:
   Rectangle(int height, int width, int length){ }
};

void draw_rect(Rectangle r);

int main() {
   draw_rect({5, 6, 9});  // Rectangle{5,6,9}被自動呼叫
}

// 注意:要小心使用
// 1. 可讀性非常差,即使有IDE的幫助也是。函式名稱很少表示函式所採用的引數型別
// 2. 函式可以被不同引數型別過載,比如下面的情況

void draw_rect(Triangle t);

2 統一初始化Uniform Initialization

// C++ 03
class Dog {     // 聚合類或者結構體,直接初始化對應成員
   public:
      int age;
      string name;
};
Dog d1 = {5, "Henry"};   // 可以直接用大括號聚合初始化

// C++ 11 擴充套件了大括號初始化的範圍
class Dog {
   public:
      Dog(int age, string name) {...};
};
Dog d1 = {5, "Henry"};  //類有合適引數的建構函式


/* 統一初始化的搜尋順序:
 * 1. 初始化列表建構函式
 * 2. 具有合適引數的常規建構函式
 * 3. 聚合初始化(直接初始化對應成員)
 */

Dog d1{3};

class Dog {
   public:
   int age;                                // 第3選擇

   Dog(int a) {                            // 第2選擇
      age = a;
   }

   Dog(const initializer_list<int>& vec) { // 第1選擇
      age = *(vec.begin());      
   }
};

3 auto型別

std::vector<int> vec = {2, 3, 4, 5};

// C++ 03
for (std::vector<int>::iterator it = vec.begin(); it!=vec.end(); ++ it)
    m_vec.push_back(*it);


// C++ 11: 使用auto節省大量打字的時間
for (auto it = vec.begin(); it!=vec.end(); ++ it)
    m_vec.push_back(*it);

auto a = 6;    // a is a integer
auto b = 9.6;  // b is a double
auto c = a;    // c is an integer
auto const x = a;   // int const x = a
auto& y = a;        // int& y = a

// 它是靜態型別,沒有執行時成本,fat-free.
// 使得程式碼更易維護

// 1. 當需要型別轉換時不要使用auto
// 2. IDE變得很重要

4. foreach

 */
// C++ 03:
   for (vector<int>::iterator itr = v.begin(); itr!=v.end(); ++ itr)
      cout << (*itr);


// C++ 11:
   for (auto i: v) { // 任何有begin()和end()的類都能使用
      cout << i ;    // 只讀訪問
   }

   for (auto& i: v) {
      i++;                 // 改變v的值,避免拷貝構造
   }                       

   auto x = begin(v);  // 同int x = v.begin();

   int arr[4] = {3, 2, 4, 5};
   auto y = begin(arr); // y == 3
   auto z = end(arr);   // z == 5
   // 因為陣列定義了begin()和end()
   // 可以通過給資料的容器定義begin()和end(),使你的程式碼適配第三方庫

5 nullptr

 * 代替C++ 03中的NULL
 */
// NULL具有二義性
void foo(int i) { cout << "foo_int" << endl; }
void foo(char* pc) { cout << "foo_char*" << endl; }

int main() {
   foo(NULL);    // 二義性,呼叫哪個函式?

   // C++ 11
   foo(nullptr); // 呼叫foo(char*)
}

6 列舉類 enum class


   // C++ 03
   enum apple {green_a, red_a};
   enum orange {big_o, small_o};
   apple a = green_a;
   orange o = big_o;

   if (a == o) //兩個不同列舉型別進行比較
      cout << "green apple and big orange are the same\n";
   else
      cout << "green apple and big orange are not the same\n";


   // C++ 11
   enum class apple {green, red};
   enum class orange {big, small};
   apple a = apple::green;
   orange o = orange::big;

   if (a == o)  //編譯失敗,因為我們沒有定義 ==(apple, orange)
      cout << "green apple and big orange are the same\n";
   else
      cout << "green apple and big orange are not the same\n";

7 static_assert


// 執行時斷言
   assert( myPointer != NULL );

// C++ 11提供了靜態斷言,在編譯時檢查
// 如果int的大小不是4,編譯不過
   static_assert( sizeof(int) == 4 );

8 委託建構函式


// 一個建構函式想複用另一個建構函式的程式碼
// 下面這種方法是錯誤的,會構造兩個物件
class Dog {
   public:
   Dog() { ... }
   Dog(int a) { Dog(); doOtherThings(a); }
};


// C++ 03的實現方法:
class Dog {
   init() { ... };
   public:
   Dog() { init(); }
   Dog(int a) { init(); doOtherThings(); }
};
/* 缺點:
 * 1. 程式碼笨重.
 * 2. 而且init()可能被其他函式呼叫
 */

// C++ 11 方法:
class Dog {
   int age = 9;
   public:
   Dog() { ... }
   Dog(int a) : Dog() { doOtherThings(); }
};
// 限制: Dog()也即被委託的建構函式必須先被呼叫