explicit用來防止由建構函式定義的隱式轉換。
要明白它的作用,首先要瞭解隱式轉換:可以用單個實參來調用的建構函式定義了從形參類型到該類類型的一個隱式轉換。
例如:
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;};
這時再進行編譯,在vs2008上會提示:沒有可用於執行該轉換的使用者定義的轉換運算子,或者無法調用該運算子。
這時你仍然可以通過顯示使用建構函式完成上面的類型轉換:
things a;................//在這裡被初始化並使用。std::string nm = "book_1";//顯示使用建構函式int result = a.CompareTo(things(nm));
google的c++規範中提到explicit的優點是可以避免不合時宜的類型變換,缺點無。所以google約定所有單參數的建構函式都必須是顯示的,只有極少數情況下拷貝建構函式可以不聲明稱explicit。例如作為其他類的透明封裝器的類。
effective c++中說:被聲明為explicit的建構函式通常比其non-explicit兄弟更受歡迎。因為它們禁止編譯器執行非預期(往往也不被期望)的類型 轉換。除非我有一個好理由允許建構函式被用於隱式類型轉換,否則我會把它聲明為explicit。我鼓勵你遵循相同的政策。