天天看點

C++隐式轉換與explicit關鍵字隐式轉換定義隐式轉換的發生條件隐式轉換的風險explicit的作用

隐式轉換定義

Implicit conversions are performed whenever an expression of some type T1 is used in context that does not accept that type, but accepts some other type T2; in particular:

  • when the expression is used as the argument when calling a function that is declared with T2 as parameter;
  • when the expression is used as an operand with an operator that expects T2;
  • when initializing a new object of type T2, including return statement in a function returning T2;
  • when the expression is used in a switch statement (T2 is integral type);
  • when the expression is used in an if statement or a loop (T2 is bool).

所謂隐式轉換,是指不需要使用者幹預,編譯器私下進行的類型轉換行為。很多時候使用者可能都不知道進行了哪些轉換。

隐式轉換的發生條件

這裡隻讨論自定義的類的隐式轉換發生條件。對于基本資料類型,隐式轉換發生在取值範圍從小->大,低精度->高精度的轉換中。

按照預設規定,隻要有一個構造函數,C++就會為這個構造函數定義一個隐式轉換,将該構造函數對應資料類型的資料轉換為該類對象。

例子:

class String{
public:
    int n;
    char * p;
    String(int n){ this->n = n; }
    String (int a, int b, int c){
        this->n = a+b+c;
    }
};

String s1 = 10; //可以:隐式轉換調用String(int n);再調用預設的複制構造函數
String s10 = {1,2,3}; 	//可以:隐式轉換調用String(int a, int b, int c);
						//再調用預設的複制構造函數
           

隐式轉換的風險

隐式轉換的風險也一般存在于自定義的類構造函數中。

例子1:

class String
{
public:
    String ( int n ); //本意是預先配置設定n個位元組給字元串
    String ( const char* p ); // 用C風格的字元串p作為初始化值
 
    //…
}
           

下面兩種寫法比較正常:

String s2 ( 10 );   //OK 配置設定10個位元組的空字元串
String s3 = String ( 10 ); //OK 配置設定10個位元組的空字元串
           

下面兩種寫法就比較疑惑了:

String s4 = 10; //編譯通過,也是配置設定10個位元組的空字元串
String s5 = ‘a’; //編譯通過,配置設定int(‘a’)個位元組的空字元串
           

s4 和s5 分别把一個int型和char型,隐式轉換成了配置設定若幹位元組的空字元串,容易令人誤解。

explicit

的作用

==通過将構造函數聲明為explicit(顯式)的方式可以抑制隐式轉換。==也就是說,explicit構造函數必須顯式調用。

class String{
public:
    int n;
    char * p;
    explicit String(int n){ this->n = n; }
    String ( const char* p ); 
    explicit String(int a, int b, int c){
        this->n = a+b+c;
    }
};

String s1 = 10; ///錯誤:不能做隐式int->String轉換
String s2(10);  //可以:調用explicit String(int n);
String s3 = String(10);//可以:調用explicit String(int n);再調用預設的複制構造函數
String s4('a'); //可以:char->int 調用explicit String(int n);
				//再調用預設的複制構造函數
String s5 = {1,2,3}; //錯誤:不能調用隐式轉換String(int a, int b, int c);
String s6(1,2,3); //可以:調用String(int a, int b, int c);
					//再調用預設的複制構造函數
String s7 = "Brian"; //可以:隐式轉換調用String(const char *p);
					 //再調用預設的複制構造函數
           

隐式轉換常常帶來程式邏輯的錯誤,而且這種錯誤一旦發生是很難察覺的。

原則上應該在所有的構造函數前加explicit關鍵字,當你有心利用隐式轉換的時候再去解除explicit,這樣可以大大減少錯誤的發生。

繼續閱讀