1. 程式人生 > >C++:30分鐘瞭解C++11新特性

C++:30分鐘瞭解C++11新特性

什麼是C++11

C++11是曾經被叫做C++0x,是對目前C++語言的擴充套件和修正,C++11不僅包含核心語言的新機能,而且擴充套件了C++的標準程式庫(STL),併入了大部分的C++ Technical Report 1(TR1)程式庫(數學的特殊函式除外)。

C++11包括大量的新特性:包括lambda表示式,型別推導關鍵字auto、decltype,和模板的大量改進。

本文將對C++11的以上新特性進行簡單的講解,以便大家能夠快速瞭解到C++11對C++的易用性方面祈禱的巨大作用。

如果您覺得本文的排版不是很舒服,可以檢視我的PDF文件:百度盤連結

新的關鍵字

auto

C++11中引入auto第一種作用是為了自動型別推導

auto的自動型別推導,用於從初始化表示式中推斷出變數的資料型別。通過auto的自動型別推導,可以大大簡化我們的程式設計工作

auto實際上實在編譯時對變數進行了型別推導,所以不會對程式的執行效率造成不良影響

另外,似乎auto並不會影響編譯速度,因為編譯時本來也要右側推導然後判斷與左側是否匹配。

  1. auto a; // 錯誤,auto是通過初始化表示式進行型別推導,如果沒有初始化表示式,就無法確定a的型別
  2. auto i = 1;  
  3. auto d = 1.0;  
  4. auto str = "Hello World";  
  5. auto ch = 'A';  
  6. auto func = less<int>();  
  7. vector<int> iv;  
  8. auto ite = iv.begin();  
  9. auto p = new foo() // 對自定義型別進行型別推導

auto不光有以上的應用,它在模板中也是大顯身手,比如下例這個加工產品的例子中,如果不使用auto就必須宣告Product這一模板引數:

  1. template <typename Product, typename Creator>  
  2. void processProduct(const Creator& creator) {  
  3.     Product* val = creator.makeObject();  
  4. // do somthing with val
  5. }         
  6.         . 

如果使用auto,則可以這樣寫:

  1. template <typename Creator>  
  2. void processProduct(const Creator& creator) {  
  3.     auto val = creator.makeObject();  
  4. // do somthing with val

拋棄了麻煩的模板引數,整個程式碼變得更加正解了。

decltype

decltype實際上有點像auto的反函式,auto可以讓你宣告一個變數,而decltype則可以從一個變數或表示式中得到型別,有例項如下:

  1. int x = 3;  
  2. decltype(x) y = x; 

有人會問,decltype的實用之處在哪裡呢,我們接著上邊的例子繼續說下去,如果上文中的加工產品的例子中我們想把產品作為返回值該怎麼辦呢?我們可以這樣寫:

  1. template <typename Creator>  
  2. auto processProduct(const Creator& creator) -> decltype(creator.makeObject()) {  
  3.     auto val = creator.makeObject();  
  4. // do somthing with val

nullptr

nullptr是為了解決原來C++中NULL的二義性問題而引進的一種新的型別,因為NULL實際上代表的是0,

  1. void F(int a){  
  2.     cout<<a<<endl;  
  3. }  
  4. void F(int *p){  
  5.     assert(p != NULL);  
  6.     cout<< p <<endl;  
  7. }  
  8. int main(){  
  9. int *p = nullptr;  
  10. int *q = NULL;  
  11. bool equal = ( p == q ); // equal的值為true,說明p和q都是空指標
  12. int a = nullptr; // 編譯失敗,nullptr不能轉型為int
  13.     F(0); // 在C++98中編譯失敗,有二義性;在C++11中呼叫F(int)
  14.     F(nullptr);  
  15. return 0;  

序列for迴圈

在C++中for迴圈可以使用類似java的簡化的for迴圈,可以用於遍歷陣列,容器,string以及由begin和end函式定義的序列(即有Iterator),示例程式碼如下:

  1. map<string, int> m{{"a", 1}, {"b", 2}, {"c", 3}};  
  2. for (auto p : m){  
  3.     cout<<p.first<<" : "<<p.second<<endl;  

Lambda表示式

lambda表示式類似Javascript中的閉包,它可以用於建立並定義匿名的函式物件,以簡化程式設計工作。Lambda的語法如下:

[函式物件引數](操作符過載函式引數)->返回值型別{函式體}

  1. vector<int> iv{5, 4, 3, 2, 1};  
  2. int a = 2, b = 1;  
  3. for_each(iv.begin(), iv.end(), [b](int &x){cout<<(x + b)<<endl;}); // (1)
  4. for_each(iv.begin(), iv.end(), [=](int &x){x *= (a + b);});     // (2)
  5. for_each(iv.begin(), iv.end(), [=](int &x)->int{return x * (a + b);});// (3)
  • []內的引數指的是Lambda表示式可以取得的全域性變數。(1)函式中的b就是指函式可以得到在Lambda表示式外的全域性變數,如果在[]中傳入=的話,即是可以取得所有的外部變數,如(2)和(3)Lambda表示式
  • ()內的引數是每次呼叫函式時傳入的引數
  • ->後加上的是Lambda表示式返回值的型別,如(3)中返回了一個int型別的變數

變長引數的模板

我們在C++中都用過pair,pair可以使用make_pair構造,構造一個包含兩種不同型別的資料的容器。比如,如下程式碼:

  1. auto p = make_pair(1, "C++ 11"); 

由於在C++11中引入了變長引數模板,所以發明了新的資料型別:tuple,tuple是一個N元組,可以傳入1個, 2個甚至多個不同型別的資料

  1. auto t1 = make_tuple(1, 2.0, "C++ 11");  
  2. auto t2 = make_tuple(1, 2.0, "C++ 11", {1, 0, 2}); 

這樣就避免了從前的pair中巢狀pair的醜陋做法,使得程式碼更加整潔

另一個經常見到的例子是Print函式,在C語言中printf可以傳入多個引數,在C++11中,我們可以用變長引數模板實現更簡潔的Print

  1. template<typename head, typename... tail>  
  2. void Print(Head head, typename... tail) {  
  3.     cout<< head <<endl;  
  4.     Print(tail...);  

Print中可以傳入多個不同種類的引數,如下:

  1. Print(1, 1.0, "C++11"); 

更加優雅的初始化方法

在引入C++11之前,只有陣列能使用初始化列表,其他容器想要使用初始化列表,只能用以下方法:

  1. int arr[3] = {1, 2, 3}  
  2. vector<int> v(arr, arr + 3); 

在C++11中,我們可以使用以下語法來進行替換:

  1. int arr[3]{1, 2, 3};  
  2. vector<int> iv{1, 2, 3};  
  3. map<int, string>{{1, "a"}, {2, "b"}};  
  4. string str{"Hello World"}; 

然後呢…

如果你想了解更多C++11令人興奮的新特性,我會向你推薦這兩個部落格:

【編輯推薦】