c++11之初始化列表
阿新 • • 發佈:2019-01-04
一、前言
C++的學習中,我想每個人都被變數定義和申明折磨過,比如我在大學筆試過的幾家公司,都考察了const和變數,型別的不同排列組合,讓你區別有啥不同。反正在學習C++過程中已經被折磨慣了,今天再來看看重溫下那段“輝煌的歷史”。先來看一段程式碼:
a,c,d 都是申明一個變數,a 很容易理解就是申明一個變數,b第一感覺是呼叫建構函式來申明變數,其實不是,而是申明一個無引數,返回Player的函式。對於c以為是呼叫了operator= 賦值運算吧?完全不是,而是先生成一個物件,然後呼叫Player的拷貝建構函式,生成物件pc。d和c是一樣的。e才是真正呼叫賦值操作。是不是已經被這各式各樣的物件申明搞的暈頭專向了。現在C++11初始化列表正式登場。
二、簡介
在看C++11初始化前,先來回憶一下C語言中的結構體初始化,程式碼如下:
結構體變數可以列表初始化,非常方便。C++11引入了初始化列表來初始化變數和物件。
三、如何使用
通過初始化列表可以彌補c中只能初始化相同數字的問題。在使用中c和d不要混淆了。
還可以返回pair型別,初始化map都是可以的。
2、自定義型別
對於單個引數初始化,型別匹配建構函式,不需要自定義建構函式。
對於上面幾種變數初始化,推薦a, 如果是帶引數的建構函式,推薦b,若果是不帶引數的建構函式。
3、如果是自己想實現初始化列表建構函式,拷貝函式,賦值函式,需要包含initializer_list 這個標頭檔案。
這是自定義類,帶有初始化列表建構函式的類,下面來練習下學過的類相關C++知識:
看一下每次呼叫都輸出什麼結果,答案在這裡:
四、為啥需要初始化列表
1、避免類申明物件混淆,區分對待,對於C++為啥有小括號初始化物件這一說,大家可以自行google,看來不管是誰都有犯錯誤的時候,勇於承認錯誤還是好同志。
2、在初始化多個變數時方便
3、避免資料切割,因為通過初始化列表是不允許隱式轉換的,相關知識可以參考我的這篇文章。
五、注意事項
1、在申明變數的時候,少用小括號,程式可讀性更高
2、使用初始化列表防止隱式轉換,減少bug
3、通過 {} 返回的物件是const型別,不可轉換
C++的學習中,我想每個人都被變數定義和申明折磨過,比如我在大學筆試過的幾家公司,都考察了const和變數,型別的不同排列組合,讓你區別有啥不同。反正在學習C++過程中已經被折磨慣了,今天再來看看重溫下那段“輝煌的歷史”。先來看一段程式碼:
Player pa; // (a) Player pb(); // (b) Player pc = Player(); // (c) Player pd(Player()); // (d) pd = Player() // (e)
a,c,d 都是申明一個變數,a 很容易理解就是申明一個變數,b第一感覺是呼叫建構函式來申明變數,其實不是,而是申明一個無引數,返回Player的函式。對於c以為是呼叫了operator= 賦值運算吧?完全不是,而是先生成一個物件,然後呼叫Player的拷貝建構函式,生成物件pc。d和c是一樣的。e才是真正呼叫賦值操作。是不是已經被這各式各樣的物件申明搞的暈頭專向了。現在C++11初始化列表正式登場。
二、簡介
在看C++11初始化前,先來回憶一下C語言中的結構體初始化,程式碼如下:
#include <iostream> struct Player{ int id; const char* name; }; int main() { Player player = {10001, "c++"}; printf("%d, %s\n", player.id, player.name); }
結構體變數可以列表初始化,非常方便。C++11引入了初始化列表來初始化變數和物件。
三、如何使用
1、系統內建型別
int ia{1}; // (a)
int ib = {1}; // (b)
int ic(1); // (c)
int id = 1; // (d)
很明顯,還是d 更符合習慣。std::vector<int> va{1, 2, 3}; // (a) std::vector<int> vb = {1, 2, 3}; // (b) std::vector<int> vc(1, 10); // (c) std::vector<int> vd{1, 10}; // (d)
通過初始化列表可以彌補c中只能初始化相同數字的問題。在使用中c和d不要混淆了。
std::pair<int, const char*> getPlayer() {
return {10001, "c++"};
}
std::map<int, const char*> players = {{10001, "c++"}, {10002, "java”}};
還可以返回pair型別,初始化map都是可以的。
2、自定義型別
對於單個引數初始化,型別匹配建構函式,不需要自定義建構函式。
Player pa{}; // (a)
Player pb; // (b)
Player pc(); // (c)
Player pd(b); // (d)
Player pe = b; // (e)
Player pf = {b}; // (f)
對於上面幾種變數初始化,推薦a, 如果是帶引數的建構函式,推薦b,若果是不帶引數的建構函式。
3、如果是自己想實現初始化列表建構函式,拷貝函式,賦值函式,需要包含initializer_list 這個標頭檔案。
class MyClass{
public:
MyClass(int a):a_(a){
std::cout << "normal initializer list\n";
}
MyClass(std::initializer_list<int> a):b_(a) {
std::cout << "initializer list constructor\n";
}
MyClass(MyClass& my) {
std::cout << "copy constructor\n";
this->a_ = my.a_;
this->b_ = my.b_;
}
MyClass& operator=(MyClass& my) {
std::cout << "operator = constructor\n";
this->a_ = my.a_;
this->b_ = my.b_;
return *this;
}
private:
int a_;
std::initializer_list<int> b_;
};
這是自定義類,帶有初始化列表建構函式的類,下面來練習下學過的類相關C++知識:
MyClass ma{1}; // (a)
MyClass mb = {1, 2, 3}; // (b)
MyClass mc(2); // (c)
MyClass md = b; // (d)
MyClass me(c); // (e)
MyClass mf{e}; // (f)
auto l{2, 2, 3,3};
MyClass mh{l}; // (e)
ma = mb; // (h)
看一下每次呼叫都輸出什麼結果,答案在這裡:
initializer list constructor
initializer list constructor
normal constructor list
copy constructor
copy constructor
copy constructor
initializer list constructor
operator = constructor
四、為啥需要初始化列表
1、避免類申明物件混淆,區分對待,對於C++為啥有小括號初始化物件這一說,大家可以自行google,看來不管是誰都有犯錯誤的時候,勇於承認錯誤還是好同志。
2、在初始化多個變數時方便
3、避免資料切割,因為通過初始化列表是不允許隱式轉換的,相關知識可以參考我的這篇文章。
五、注意事項
1、在申明變數的時候,少用小括號,程式可讀性更高
2、使用初始化列表防止隱式轉換,減少bug
3、通過 {} 返回的物件是const型別,不可轉換