天天看點

《深入了解C++11:C++ 11新特性解析與應用》——2.7 快速初始化成員變量

類别:部分人

在c++98中,支援了在類聲明中使用等号“=”加初始值的方式,來初始化類中靜态成員常量。這種聲明方式我們也稱之為“就地”聲明。就地聲明在代碼編寫時非常便利,不過c++98對類中就地聲明的要求卻非常高。如果靜态成員不滿足常量性,則不可以就地聲明,而且即使常量的靜态成員也隻能是整型或者枚舉型才能就地初始化。而非靜态成員變量的初始化則必須在構造函數中進行。我們來看看下面的例子,如代碼清單2-14所示。

《深入了解C++11:C++ 11新特性解析與應用》——2.7 快速初始化成員變量

在代碼清單2-14中,成員c、靜态成員d、靜态常量成員e以及靜态常量指針f的就地初始化都無法通過編譯(這裡,使用g++的讀者可能發現就地初始化double類型靜态常量e是可以通過編譯的,不過這實際是gnu對c++的一個擴充,并不遵從c++标準)。在c++11中,标準允許非靜态成員變量的初始化有多種形式。具體而言,除了初始化清單外,在c++11中,标準還允許使用等号=或者花括号{}進行就地的非靜态成員變量初始化。比如:

在這個名叫init的結構體中,我們給了非靜态成員a和b分别賦予初值1和1.2。這在c++11中是一個合法的結構體聲明。雖然這裡采用的一對花括号{}的初始化方法讀者第一次見到,不過在第3章中,讀者會在c++對于初始化表達式的改動發現,花括号式的集合(清單)初始化已經成為c++11中初始化聲明的一種通用形式,而其效果類似于c++98中使用圓括号()對自定義變量的表達式清單初始化。不過在c++11中,對于非靜态成員進行就地初始化,兩者卻并非等價的,如代碼清單2-15所示。

《深入了解C++11:C++ 11新特性解析與應用》——2.7 快速初始化成員變量

從代碼清單2-15中可以看到,就地圓括号式的表達式清單初始化非靜态成員b和c都會導緻編譯出錯。

在c++11标準支援了就地初始化非靜态成員的同時,初始化清單這個手段也被保留下來了。如果兩者都使用,是否會發生沖突呢?我們來看下面這個例子,如代碼清單2-16所示。

《深入了解C++11:C++ 11新特性解析與應用》——2.7 快速初始化成員變量
《深入了解C++11:C++ 11新特性解析與應用》——2.7 快速初始化成員變量

在代碼清單2-16中,我們定義了有兩個初始化函數的類mem,此外還定義了包含兩個mem對象的group類。類mem中的成員變量num,以及class group中的成員變量a、b、val,采用了與c++98完全不同的初始化方式。讀者可以從main函數的列印輸出中看到,就地初始化和初始化清單并不沖突。程式員可以為同一成員變量既聲明就地的清單初始化,又在初始化清單中進行初始化,隻不過初始化清單總是看起來“後作用于”非靜态成員。也就是說,初始化清單的效果總是優先于就地初始化的。

相對于傳統的初始化清單,在類聲明中對非靜态成員變量進行就地清單初始化可以降低程式員的工作量。當然,我們隻在有多個構造函數,且有多個成員變量的時候可以看到新方式帶來的便利。我們來看看下面的例子,如代碼清單2-17所示。

《深入了解C++11:C++ 11新特性解析與應用》——2.7 快速初始化成員變量
《深入了解C++11:C++ 11新特性解析與應用》——2.7 快速初始化成員變量

在代碼清單2-17中,group有4個構造函數。可以想象,如果我們使用的是c++98的編譯器,我們不得不在group()、group(int a),以及group(mem m)這3個構造函數中将data、mem、name這3個成員都寫進初始化清單。但如果使用的是c++11的編譯器,那麼通過對非靜态成員變量的就地初始化,我們就可以避免重複地在初始化清單中寫上每個非靜态成員了(在c++98中,我們還可以通過調用公共的初始化函數來達到類似的目的,不過目前在書寫的複雜性及效率性上遠低于c++11改進後的做法)。

此外,值得注意的是,對于非常量的靜态成員變量,c++11則與c++98保持了一緻。程式員還是需要到頭檔案以外去定義它,這會保證編譯時,類靜态成員的定義最後隻存在于一個目标檔案中。不過對于靜态常量成員,除了const關鍵字外,在本書第6章中我們會看到還可以使用constexpr來對靜态常量成員進行聲明。

繼續閱讀