C++ 11語法甜點1


      C++ 11中引入了許多簡化編程工作的語法上的新特性,我們暫且美其名曰“語法甜點”。下面一一進行介紹。
      語法甜點1:序列for循環
      序列for循環是一種簡化的for循環,可用於遍歷一組序列,包括各種容器、string、數組、初始化列表以及由begin和end函數定義的序列。示例代碼如下:

1  vector<int> vctTemp{1, 2, 3};
2  for (auto a : vctTemp)
3  {
4   cout << a << endl;
5  }

 

      語法甜點2:委託構造函數
      在引入C++ 11之前,如果某個類有多個重載的構造函數,且這些構造函數中有一些共同的初始化邏輯,通常都需要再編寫一個帶參數的初始化函數,然後在這些構造函數中調用這個初始化函數。在C++ 11中,再也不用這麼麻煩了。我們可以實現一個最基礎的構造函數,其他構造函數都調用這個構造函數。示例代碼如下:

複製代碼
 1 class CPerson
 2 {
 3 public:
 4  CPerson() : CPerson(0, "") { NULL; }
 5  CPerson(int nAge) : CPerson(nAge, "") { NULL; }
 6  CPerson(int nAge, const string &strName)
 7  {
 8   stringstream ss;
 9   ss << strName << "is " << nAge << "years old.";
10   m_strInfo = ss.str();
11  }
12 
13 private:
14  string m_strInfo;
15 };
複製代碼

     

      語法甜點3:統一的初始化語法
      在引入C++ 11之前,有各種不同的初始化語法。在C++ 11中,仍可以使用這些初始化語法,但也可以選擇使用新引入的統一的初始化語法。統一的初始化語法用一對大括號{}表示,使用{}初始化語法還可有效地避免窄轉換。示例代碼如下:

複製代碼
1  int a{5};
2  char c{'X'};
3  int p[5] = {1, 2,3, 4, 5};
4  vector<int> vctTemp{1, 2, 3};
5  CPerson person{10, "Mike"};
6   int b = 5.3;                     // b賦值成5,發生了窄轉換
7   int d{5.3};                      // 會提示編譯錯誤,避免了窄轉換
複製代碼

 

      語法甜點4:nullptr
      nullptr是C++ 11中新加的一個關鍵字,用於標識空指針。引入nullptr後,可以解決某些函數重載時的二義性問題。示例代碼如下:

複製代碼
 1 void F(int a)
 2 {
 3  cout << a << endl;
 4 }
 5 
 6 void F(char *p)
 7 {
 8  assert(p != NULL);
 9 
10  cout << p << endl;
11 }
12 
13 int main(int argc, _TCHAR* argv[])
14 {
15  int *p = nullptr;
16  int *q = NULL;
17  bool bEqual = (p == q);  // 兩個指針值是相等的,bEqual爲true
18  int a = nullptr;   // 編譯失敗,nullptr不是轉換爲int
19 
20  F(0);          // 在C++ 98中編譯失敗,有二義性;在C++ 11中調用F(int)
21  F(nullptr);    // 調用F(char *)
22 
23  getchar();
24  return 0;
25 }
複製代碼

     

      語法甜點5:成員變量初始化
      與Java和C#中的用法一樣,可以對成員變量進行就地初始化。示例代碼如下:

1 class CPerson
2 {
3 private:
4  int m_nAge = 10;
5  string m_strName = "Mike";
6 };

 

      語法甜點6:默認或禁用函數
      當我們定義了自己的帶參數的構造函數時,編譯器將不再生成默認的構造函數,如果此時想使用默認的構造函數,則必須顯式地聲明並定義不帶參數的構造函數。在C++ 11中,我們可以使用default關鍵字來表明我們希望使用默認的構造函數。類似的,當我們不想外部使用編譯器自動生成的構造函數或賦值函數時,我們一般需要將其聲明成protected或private的。在C++ 11中,我們可以使用delete關鍵字來表明我們不希望編譯器生成默認的構造函數或賦值函數。示例代碼如下:

1 class CPerson
2 {
3 public:
4  CPerson() = default;
5  CPerson(const CPerson &person) = delete;
6 };

 

      語法甜點7:繼承的構造函數
      當一個派生類的某個函數隱藏了基類中的某個同名函數時,如果我們想在派生類中導出基類中的這個同名函數,可以通過using Base::Func的方式將基類中的這個同名函數引入到派生類的作用域內。當該方法只對普通成員函數有效,不能用於構造函數。在C++ 11中,如果派生類認爲基類的構造函數已經足夠,則也可以使用using Base::Base的方式將基類的構造函數引入到派生類的作用域內。但需要注意的是,此時派生類中的成員變量並沒有進行初始化,所以應當對這些成員變量進行就地初始化。示例代碼如下:

複製代碼
 1 class CBase
 2 {
 3 };
 4 
 5 class CDerived : public CBase
 6 {
 7 public:
 8  using CBase::CBase;
 9  CDerived(int nData) : m_nData(nData) { NULL; }
10 
11 private:
12  int m_nData = 10;
13 };
複製代碼

 

      語法甜點8:模板右邊雙括號
      在C++ 98中,vector<vector<int>> vctTemp是一個非法的表達式,編譯器會認爲右邊的>>是一個移位操作符,因此必須修改爲vector<vector<int> > vctTemp,即在右邊的兩個>中間添加一個空格。在C++ 11中,這將不再是一個問題,編譯器將能夠識別出右邊的雙括號是兩個模板參數列表的結尾。

 

      語法甜點9:static_assert
      靜態斷言static_assert由一個常量表達式和一個字符串構成。在編譯期間,將計算常量表達式的值,如果爲false,字符串將作爲錯誤信息輸出。示例代碼如下:

1  char a = 10;
2  static_assert(sizeof(a)==4, "a is not an integer.");

 

      語法甜點10:初始化列表
      在引入C++ 11之前,只有數組能使用初始化列表。在C++ 11中,vector、list等各種容器以及string都可以使用初始化列表了。初始化列表對應的類爲initializer_list,vector、list等各種容器以及string之所以可以使用初始化列表,是因爲它們重載了參數類型爲initializer_list的構造函數(稱爲初始化列表構造函數)和賦值函數(稱爲初始化列表賦值函數)。下面是一些使用初始化列表的例子。

複製代碼
 1 void Print(const initializer_list<int> &ilData)
 2 {
 3  for (auto a : ilData)
 4  {
 5   cout << a << endl;
 6  }
 7 }
 8 
 9 int main(int argc, _TCHAR* argv[])
10 {
11  vector<int> vctNum = {1, 2, 3, 4, 5};
12  map<string, string> mapID2Name = {{"92001", "Jack"}, {"92002", "Mike"}};
13  string strText{"hello world"};
14  Print({});
15  Print({1, 2});
16  Print({1, 2, 3, 4, 5});
17 
18  getchar();
19  return 0;
20 }
複製代碼
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章