閱讀了 effective c++中關於初始化部分知識,其中提到了explicit關鍵字
explicit作用: 防止構造函數執行隱式類型轉換
要明白它的作用,首先要了解隱式轉換:
我們來構造一個隱式調用
方法:可以用單個實參來調用的構造函數定義了從形參類型到該類類型的一個隱式轉換。
例如:
class B{ public: B(int x); void dosomething(B bobject); }
然後有一個操作調用dosomething
如下:
dosomething(20);dosomething中形參類型為B,但是這裡用的20,實際上是可以執行的
因為這裡的20 調用了 構造函數B(20) 成為了一個B對象
再如下:
class things { public: things(const std::string&name =""): m_name(name),height(0),weight(10){} int CompareTo(const things & other); std::string m_name; int height; int weight; };
這裡things的構造函數可以只用一個實參完成初始化。所以可以進行一個隱式轉換,像下面這樣:
things a;
................//在這裡被初始化並使用。
std::string nm ="book_1";
//由於可以隱式轉換,所以可以下面這樣使用
int result = a.CompareTo(nm);
這段程序使用一個string類型對象作為實參傳給things的CompareTo函數。這個函數本來是需要一個tings對象作為實參。現在編譯器使用string nm來構造並初始化一個
things對象,新生成的臨時的things對象被傳遞給CompareTo函數,並在離開這段函數後被析構。
這種行為的正確與否取決於業務需要。假如你只是想測試一下a的重量與10的大小之比,這麼做也許是方便的。但是假如在CompareTo函數中還涉及到了要除以初始化為0的height屬性,那麼這麼做可能就是錯誤的。需要在構造tings之後更改height屬性不為0。所以要限制這種隱式類型轉換。
那麼這時候就可以通過將構造函數聲明為explicit,來防止隱式類型轉換。
explicit關鍵字只能用於類內部的構造函數聲明上,而不能用在類外部的函數定義上。現在things類像這樣:
class things { public: explicit things(const std::string&name =""): m_name(name),height(0),weight(0){} int CompareTo(const things & other); std::string m_name; int height; int weight; };
這時你仍然可以通過顯示使用構造函數完成上面的類型轉換:
things a;
................//在這裡被初始化並使用。
std::string nm ="book_1";
//顯示使用構造函數
int result = a.CompareTo(things(nm));
google的c++規范中提到explicit的優點是可以避免不合時宜的類型變換,缺點無。所以google約定所有單參數的構造函數都必須是顯示的,只有極少數情況下拷貝構造函數可以不聲明稱explicit。例如作為其他類的透明包裝器的類。
effective c++中說:被聲明為explicit的構造函數通常比其non-explicit兄弟更受歡迎。因為它們禁止編譯器執行非預期(往往也不被期望)的類型轉換。除非我有一個好理由允許構造函數被用於隱式類型轉換,否則我會把它聲明為explicit。我鼓勵你遵循相同的政策。