1. 程式人生 > 實用技巧 >第41課 - 型別轉換函式(上)

第41課 - 型別轉換函式(上)

1.再論型別轉換(隱式轉化和強制型別轉換)

(1)標準資料型別之間會進行隱式型別安全轉換

(2)轉換規則

      

8個位元組 long: 8個位元組 long long: 8個位元組 unsigned long: 8個位元組

小型別(佔用記憶體小)--->大型別(佔用記憶體大)-----隱式轉化(安全,不會發生程式的截斷和資料的丟失)

實驗:程式設計避免不同型別轉換,編譯器進行的隱式轉換很可怕

 1 #include<iostream> 
 2 #include<string>
 3 
 4 using namespace std;
 5 
 6 int
main() 7 { 8 short s = 'a'; 9 unsigned int ui = 1000; //unsigned_-->int 10 int i = -2000; 11 double d = i; //小型別初始化大型別是安全的 12 13 cout << d << endl; //-2000 14 cout << ui<< endl; //1000 15 cout << ui+i << endl; //驗證:ui+i =4294966296 16 17
//因為i會被轉為unsigned int型別,兩個無符號整形數相加,變成一個很大的正數。 18 //程式設計避免隱式型別轉換 19 20 if ((ui + i) > 0) //編譯器進行隱式型別轉換,將i(小型別)轉換為unsigned int(大型別) 21 { 22 cout << "positive" << endl; //negative 23 } 24 else 25 { 26 cout << "
negative" << endl; 27 } 28 29 //根據標準資料型別的轉換規則s->int。'b'為char,也會被轉為int型。所以輸出4 30 31 cout << "sizeof(s+'b')=" << sizeof(s + 'b') << endl; //4 32 //編譯期將s和b都轉換為Int 33 return 0; 34 }

問題:

實驗:普通到類型別

 1 #include<iostream>     
 2 #include<string>
 3 
 4 using namespace std;
 5 
 6 //類之間可不可以進行型別轉換
 7 class Test
 8 {
 9     int mvalue;
10 public:
11     Test()
12     {
13     }
14 
15     Test(int i)   //轉換建構函式
16     {
17         mvalue = i;
18     }
19     Test operator + (const Test& p)
20     {
21         Test ret(mvalue + p.mvalue);
22 
23         return ret;
24     }
25 
26     int value()
27     {
28         return mvalue;
29     }
30     
31 };
32 int main()
33 {
34     Test t;
35 
36     //    t = (Test)5; //型別怎麼轉換????
37     //  t = Test(5); //直接呼叫建構函式,會產生一個臨時物件,臨時物件賦值給t物件,他倆屬於Test物件
38                      //編譯器進行隱式型別轉換-----本質呼叫轉換建構函式
39                         
40     t = 5;        //沒有轉化建構函式之前,錯誤
41                 //有轉換建構函式定義,等價於t=Test(5); 正確
42 
43     Test r;
44     r = t + 10;      //相當於:r = t + Test(10); 手誤10整形,將2個Test物件相加,呼叫建構函式----error
45 
46     cout << r.value() << endl;  //15  
47 
48     return 0;
49 }

2.普通型別到類型別的轉換——轉換建構函式

也可以將其他類型別轉換到當前類型別

(1)建構函式可以定義不同型別的引數

(2)引數滿足下列條件時稱為轉換建構函式

  ①有且僅有一個引數

  ②引數是基本型別

  ③引數是其它類型別但不是本類的const引用,因為那叫拷貝建構函式

(3)另一個視角:舊式的C方式強制型別轉換

int i = int(1.5);   //將浮點轉為整型,有點像函式呼叫

Test t;
t = Test(100); //老舊的C轉換方式,100整形強制型別轉換到類型別,本質---呼叫建構函式 有點像函式呼叫

但是這樣子隱式轉化是不好的,實驗說明:和上面一樣

Test r;
r = t + 10; //相當於:r = t + Test(10); 手誤10整形,將2個Test物件相加,呼叫建構函式----error

cout << r.value() << endl; //15

怎麼解決?????

3. explicit關鍵字-----

1)編譯器隱式轉換行為:

  ①編譯器盡力嘗試讓原始碼通過編譯

Test t;

t = 100;  //100這個立即數,預設為int型,怎麼可能賦值給t物件呢?現在就報錯

          //嗎?不急,編譯器會看看有沒有轉換建構函式!Ok,發現Test類中定義

          //Test(int i),可以進行轉換,預設等價於:t = Test(100);

  ②隱式型別轉換會讓程式以意想不到的方式進行工作,是工程中Bug的重要來源

(2)杜絕編譯器的隱式型別轉換explicit關鍵字

  ①用explicit修飾轉換建構函式。這時會阻止編譯器隱式地嘗試呼叫這個函式的行為

  ②當轉換建構函式explicit修飾時,只能手動進行顯式的轉換轉換方式:

    • A.static_cast<ClassName>(value); //C++

    • B.ClassName(value); //C--手動呼叫建構函式

    • C.(ClassName)value; //不推薦

轉換建構函式之前加了explicit----編譯器不會自動呼叫轉換建構函式,需要手動呼叫

 1 #include <iostream>
 2 
 3 using namespace std;
 4 
 5 class Test
 6 {
 7     int mValue;
 8 
 9 public:
10 
11     Test() { mValue = 0; }
12 
13     explicit Test(int i)            //轉換建構函式
14     {
15         mValue = i;
16     }
17 
18     Test operator + (const Test& p)
19     {
20         Test ret(mValue + p.mValue);
21 
22         return ret;
23     }
24 
25     int value()
26     {
27         return mValue;
28     }
29 
30 };
31 
32 
33 
34 int main()
35 {
36     Test t;
37 
38     //t = 5; //error,將5賦值給t物件,編譯器會嘗試呼叫Test(int i)轉換建構函式
39 
40              //但由於Test(int i)前面用explicit修飾,以後拒絕了這種嘗試。所以
41 
42              //編譯不通過。
43 
44 
45     t = static_cast<Test>(5); //相當於 t = Test(5); 原因:Test(int i)被explicit修飾,
46 
47                               //就是告訴編譯器要阻止那種通過隱式呼叫該函式的行為發生。
48 
49                               //只有顯式呼叫Test(int i)(或通過強制型別方式轉換的)
50 
51                               //才允許呼叫這個函式來進行型別的轉換。
52 
53 
54     Test r;
55 
56     //r = t + 10;  error
    
    t=(Test)5; //c語言方式,不推薦 57 58 r = t + static_cast<Test>(10); //c++推薦寫法 59 60 cout << r.value() << endl; //15; 61 62 return 0; 63 }

4.小結

(1)轉換建構函式只有一個引數explicit Test(int i)

(2)轉換建構函式引數型別其它型別

(3)轉換建構函式型別轉換被呼叫

(4)隱式型別轉換工程中Bug的重要來源

(5)explicit關鍵字用於杜絕編譯器這種隱式型別轉換的行為