C++11--20分鐘瞭解C++11 (上)
阿新 • • 發佈:2018-12-29
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()也即被委託的建構函式必須先被呼叫