網上有很多關于pos機初始化失敗103,C++11 精要學習的知識,也有很多人為大家解答關于pos機初始化失敗103的問題,今天pos機之家(www.www690aa.com)為大家整理了關于這方面的知識,讓我們一起來看下吧!
本文目錄一覽:
pos機初始化失敗103
引言變量初始化的工作,要是不細想,可能會覺得是一件挺簡單的事兒,例如int a = 100;。但在 C++ 的世界里,誰也不敢說哪件事是簡單的,要是寫成int a = {100};,不知道你有沒有見過?
其實后一種寫法是列表初始化方法,是 C++11 標準里定義的,它的結果也和前一種一樣。我們在下文會對列表初始化的用法、原理,以及如何避坑進行詳細討論。
如果這個變量int a是出現在類的聲明中,那又有什么新花樣對它進行默認初始化呢?我們就從類的非靜態成員默認初始化說起吧。
非靜態成員默認初始化這要從一個痛點說起。
在 C++11 標準之前,如果一個類的非靜態數據成員較多,那么用初始化列表方式,編寫構造函數時就會比較痛苦。如下例所示,會發現這幾乎就是在窮舉各種情況。
class OneInit { public: OneInit() : x(0), y(false), z("init") {} OneInit(int x) : x(x), y(false), z("init") {} OneInit(bool y) : x(0), y(y), z("init") {} OneInit(const string &z) : x(0), y(0), z(z) {} private: int x; bool y; string z;};
這還僅是舉個栗子,實際情況里一個類里十來個成員是常有的事,真要這樣寫默認初始化,費勁不說,還容易出錯。
C++11 提供了新的初始化方法,就是在類內聲明處,直接對非靜態成員賦值即可。經過改寫,看下新的版本:
class OneInit { public: OneInit() {} OneInit(int x) : x(x) {} OneInit(bool y) : y(y) {} OneInit(const string &z) : z(z) {} private: int x = 0; bool y = false; string z{"init"}; //這是列表初始化方法,下節會具體講述};
是不是簡化得多了,是不是有一種清爽感撲面而來?構造函數里,只關注你想初始化的成員就好,所有默認值都可以放在聲明處,一次性解決。
雖然方便,但仍有兩點注意事項,以免掉坑。
第一,不要使用括號()對非靜態數據成員進行初始化;第二,不要使用auto關鍵字聲明和初始化非靜態數據成員。其實你真用了上面的方法,編譯也會報錯,只是要知道錯在哪里。
列表初始化在介紹列表初始化之前,我們先回顧一下已有的兩種初始化方式:直接初始化和拷貝初始化。
直接初始化一般使用括號方式,將初始值賦予變量。而拷貝初始化,則是使用等號對變量進行初始化。
示例代碼如下:
class OneInit { public: OneInit(int x) {}};int main() { OneInit one(100); // 直接初始化 OneInit one2 = 101; // 拷貝初始化 OneInit *one3 = new OneInit(102); // 思考題:這是哪種初始化類型?}
需要注意的是,拷貝初始化的等號并不是賦值的含義,而是隱式調用構造函數。如果在構造函數前加上explicit關鍵字,則編譯會失敗。explicit的作用就是強制構造函數必須顯式調用。
那么,我們來看一下 C++11 中新增的列表初始化的方法,它使用花括號{}對變量進行初始化。列表初始化也有直接和拷貝兩種初始化類型。
還是用代碼說話:
class OneInit { public: OneInit(int x, string y) {}};int main() { OneInit one{100, "init"}; // 直接初始化 OneInit one2 = {101, "init"}; // 拷貝初始化 OneInit *one3 = new OneInit{102, "init"}; // 直接初始化,知道上面思考題的答案了吧}
上述代碼在構造函數中增加了一個string類型參數,以方便大家看到,在多參數的情況下,如何編寫列表初始化方法。
乍一看,這似乎和括號初始化方式差別不大,但它有一個妙用,就是在使用函數返回對象的時候,可以用列表初始化方式進行多參數的隱式構造,看代碼來體會一下:
class OneInit { public: OneInit(int x, string y) {}};OneInit get_object() { return {103, "init"}; // 簡化了生成對象的過程}int main() { OneInit one = get_object();}
相信大家對列表初始化的規則已經了解,下面我們講一個高階應用。
容器初始化我們對于數組可以方便地以int array[] = {1, 2, 3};這樣的方法來初始化。但是對于 STL 庫中的眾多容器,以前卻沒什么好辦法,只能寫一個循環不斷地追加值。
現在借助于列表初始化,我們也可以做到像數組一樣初始化容器對象了。
int main() { int array1[]{1, 2, 3}; int array2[] = {1, 2, 3}; vector<int> v1{1, 2, 3}; vector<int> v2 = {1, 2, 3}; list<int> l1{1, 2, 3}; list<int> l2 = {1, 2, 3}; map<string, int> m1{ {"one", 1}, {"two", 2}, {"three", 3} }; map<string, int> m2 = { {"one", 1}, {"two", 2}, {"three", 3} };}
STL 容器對象的初始化,看起來也如絲般光滑了。這個實現離不開一個前提,就是容器類要支持std::initializer_list為形參的構造函數。
std::initializer_list是一個支持begin, end, size成員函數的類模板。編譯器首先將花括號的內容構造為一個std::initializer_list對象,然后匹配容器類的構造函數,只要形參是std::initializer_list類型,那么執行相應的構造函數。
在構造函數中對begin, end范圍內的數據進行循環,就實現了多參數元素的初始化。說起來真不復雜,各位有心的完全可以自己定義一個類,然后支持std::initializer_list形參的構造函數,也能實現自有的列表初始化方法了。
不知道你注意到沒有,map 的初始化有點與眾不同,對于多參數的元素,似乎只管嵌套就完了。如果深究的話,你會發現內層元素{"one", 1}其實是隱式調用了std::pair構造函數,而外層則是走的std::initializer_list方式。
注意事項列表初始化容易掉坑的地方,就是在隱式縮窄轉換上。例如int a = 10240; char b = a;中,變量 b 的初始化就發生了隱式縮窄,信息發生了丟失。這種問題編譯時有可能警告都不會有,所以要千萬小心。
要避免這樣的問題,需要知道四條隱式縮窄規則:
從浮點類型轉換到整數類型;從long double轉換到long或float。或從double轉換到float;從整數類型或非強枚舉類型,轉換到浮點類型;從整數類型或非強枚舉類型,轉換到不能代表所有原始類型值的整數類型。以下代碼是錯誤示例,請仔細看:
int main() { int a = 10240; double b = 99.9; int c = {3.0}; // 對應規則1 float d = {b}; // 對應規則2 float e = {a}; // 對應規則3 char f = {a}; // 對應規則4}結語
沒想到一個變量初始化,也能整出這么多說法來。即使是一件看起來應該簡單的事情,在 C++ 里面也能不斷挖出坑來。所以誰也不敢說自己是 C++ 高手,那是分分鐘被打臉。
不管怎樣,讓我們記住本文最重要的三個點,方便自己以后寫代碼吧:
類的非靜態成員,可以在聲明處直接初始化;使用列表初始化方法,簡化多參數構造函數隱式執行;STL 容器對象,可直接使用列表初始化方法。參考資料:
謝丙堃 現代C++語言核心特性解析 人民郵電出版社
以上就是關于pos機初始化失敗103,C++11 精要學習的知識,后面我們會繼續為大家整理關于pos機初始化失敗103的知識,希望能夠幫助到大家!
