c++中的類型轉換

目錄

  1. 隱式類型轉換ios

  2. 強制類型轉換( static_castconst_castreinterpret_castdynamic_castc++

  3. 類型轉換函數、轉換構造函數安全

 

  類型轉換可分爲 隱式類型轉換(編譯器自動完成) 與 強制類型轉換(須要本身操做)。ide

隱式類型轉換  

  基本數據類型之間會進行隱式的類型安全轉換。其轉換規則以下:函數

  

   咱們用 1個案列來介紹這種隱式類型轉換規則,會有意想不到的結果發生....!!!測試

 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;
10     int i = -2000;
11     double d = i;
12     
13     cout << "d = " << d << endl;
14     cout << "ui = " << ui << endl;
15     cout << "ui + i = " << ui + i << endl;
16     
17     if( (ui + i) > 0 )  // 變量i會進行隱式類型轉換 -> unsigned int  // ui + i > 0
18     {
19         cout << "Positive" << endl;
20     }
21     else
22     {
23         cout << "Negative" << endl;
24     }
25     
26     cout << "sizeof(s + 'b') = " << sizeof(s + 'b') << endl;    // 4 // s -> int  'b' -> int // sizeof(s + 'b') = sizeof(int) // 編譯器默認是int運算
27     
28     return 0;
29 }
30 /*
31     d = -2000
32     ui = 1000
33     ui + i = 4294966296
34     Positive
35     sizeof(s + 'b') = 4
36 */
基本類型的隱式類型轉換案列

  在c++中,還有其它幾種隱式類型轉換(後續講解),那麼如今試想一下這幾個問題:ui

    1. 基本類型 能夠轉換爲 類類型嗎?--- 能夠,見轉換構造函數;spa

    2. 類類型 能夠轉換爲 基本類型嗎?--- 能夠,見類型轉換函數;3d

    3. 類類型之間能夠轉換嗎?--- 能夠,見轉換構造函數 和 類型轉換函數;指針

  注:這種隱式類型轉換不可以抑制,而且也是bug的來源之一;

強制類型轉換

  在介紹c++強制類型轉換前,咱們能夠回顧一下c語言中的強制類型轉換。c語言中的強制類型轉換十分簡單、粗暴,即 (Type)(Expression);或者 Type(Expression);可是,這種簡單的強制類型轉換引起了不少問題,可概括爲以下2點:

  1. 任意類型之間均可以進行轉換,編譯器很難判斷其正確性(過於粗暴);

  2. 在源碼中沒法快速定位全部使用強制類型轉換的語句(很難定位);

因此,基於這2點考慮,在c++中引入了新式類型轉換( static_castconst_castreinterpret_castdynamic_cast),其使用方法可概括爲 xxx_cast<Type>(Expression)

一、static_cast

  1. 用於 基本類型間的轉換

  2. 不能用於基本類型指針間的轉換

  3. 用於有繼承關係類對象之間的轉換和類指針之間的轉換

  4. 用於 其它類型(基本類型和類類型) 向 類類型之間的轉換;static_cast<類類型>(其它類型),見轉換構造函數。

二、 const_cast

  1. 用於去除變量的只讀屬性

  2. 強制轉換的目標類型必須是指針或引用

三、 reinterpret_cast

  1. 用於指針類型間的強制轉換

  2. 用於整數和指針類型間的強制轉換

四、 dynamic_cast

  1. 用於有繼承關係的類指針(引用)間的轉換

  2. 用於有交叉關係的類指針(引用)間的轉換

  3. 相關類(基類)中必須有虛函數的支持

  4. 具備類型檢查的功能,但類型轉換的結果只可能在運行階段獲得;

  指針轉換:

    轉換成功:獲得目標類型的指針;

    轉換失敗:獲得一個空指針;

  引用轉換: 

    轉換成功:獲得目標類型的引用;

    轉換失敗:獲得一個異常操做的信息;

  dynamic_cast 轉換時錯誤提示:

    1. 不能將父類指針 直接 轉換爲 子類指針

      

        

     2. 在 父類中沒有虛函數,不能發生多態 polymorphic

      

       

 1 #include <stdio.h>
 2 
 3 void static_cast_demo()
 4 {
 5     int i = 0x12345;
 6     char c = 'c';
 7     int* pi = &i;
 8     char* pc = &c;
 9     
10     c = static_cast<char>(i);
11     pc = static_cast<char*>(pi);    // error static_cast 不能用於基本類型指針之間 的轉換
12 }
13 
14 void const_cast_demo()
15 {
16     const int& j = 1;
17     int& k = const_cast<int&>(j);
18     
19     const int x = 2;
20     int& y = const_cast<int&>(x);
21     
22     int z = const_cast<int>(x);     // error const_cast 強制轉換的目標類型必須是指針或引用類型
23     
24     k = 5;
25     
26     printf("k = %d\n", k);  // 5
27     printf("j = %d\n", j);  // 5
28     
29     y = 8;
30     
31     printf("x = %d\n", x);  // 2
32     printf("y = %d\n", y);  // 8
33     printf("&x = %p\n", &x);// 0x7fffd40b84e8
34     printf("&y = %p\n", &y);// 0x7fffd40b84e8
35 }
36 
37 void reinterpret_cast_demo()
38 {
39     int i = 0;
40     char c = 'c';
41     int* pi = &i;
42     char* pc = &c;
43     
44     pc = reinterpret_cast<char*>(pi);
45     pi = reinterpret_cast<int*>(pc);
46     pi = reinterpret_cast<int*>(i);
47     c = reinterpret_cast<char>(i);  // error reinterpret_cast 適用於指針類型之間的轉換  和 整型與指針類型之間的轉換
48 }
49 
50 void dynamic_cast_demo()
51 {
52     int i = 0;
53     int* pi = &i;
54     char* pc = dynamic_cast<char*>(pi); // error
55 }
56 
57 int main()
58 {
59     static_cast_demo();
60     const_cast_demo();
61     reinterpret_cast_demo();
62     dynamic_cast_demo();
63     
64     return 0;
65 }
static_cast、const_cast、reinterpret_cast、dynamic_cast 初體驗

 

 1 #include <iostream>
 2 #include <string>
 3 
 4 using namespace std;
 5 
 6 class Base
 7 {
 8 public:
 9     Base()
10     {
11         cout << "Base::Base()" << endl;
12     }
13     
14     virtual ~Base()
15     {
16         cout << "Base::~Base()" << endl;
17     }
18 };
19 
20 class Derived : public Base
21 {
22 public:
23     Derived()
24     {
25         cout << "Derived::Derived()" << endl;
26     }
27     
28     void func()
29     {
30         cout << "Derived::func()" << endl;
31     }
32     
33     virtual ~Derived()
34     {
35         cout << "Derived::~Derived()" << endl;
36     }
37 };
38 
39 void test1()
40 {
41     Base* bp = new Derived();
42     
43     Derived *dp = dynamic_cast<Derived*>(bp);   // 當父類指針指向的是子類對象,轉換成功
44     //Derived *dp = static_cast<Derived*>(bp);  // 當父類指針指向的是子類對象,轉換成功
45     if( dp != NULL )
46     {
47         cout << "dp = " << dp << endl;
48         dp->func();
49     }
50     else
51     {
52         cout << "Cast error!" << endl;
53     }
54     
55     delete bp;
56 }
57 
58 void test2()
59 {
60     Base* bp = new Base();
61     
62     Derived *dp = dynamic_cast<Derived*>(bp);   // 轉化失敗,不能將父類指針對象轉換爲子類指針對象
63     //Derived *dp = static_cast<Derived*>(bp);     // 轉換成功,能夠將父類指針對象轉換爲子類指針對象
64     if( dp != NULL )
65     {
66         cout << "dp = " << dp << endl;
67         dp->func();
68     }
69     else
70     {
71         cout << "Cast error!" << endl;
72     }
73     
74     delete bp;
75 }
76 
77 int main()
78 {
79     test1();
80     
81     cout << "-----------------------" << endl;
82     
83     test2();
84 
85     return 0;
86 }
static_cast 與 dynamic_cast 測試案列

  經過 《 static_cast 與 dynamic_cast 測試案列 》可知,當使用 dynamic_cast 強制類型轉換時,即 Derived *dp = dynamic_cast<Derived*>(bp); 程序的運行結果爲:

          

   當使用 static_cast 強制類型轉換時,即 Derived *dp = static_cast<Derived*>(bp); 程序的運行結果爲:

         

  從運行結果可知, static_cast 與 dynamic_cast 在繼承中進行類指針轉換時是存在差別的;其中,

    1. 相同點:當父類指針 指向 子類對象時,兩者均可以將父類指針 成功轉換爲 子類指針;

      

     2. 不一樣點:當父類指針 指向 父類對象時,

      1) static_cast 轉換:能夠將父類指針 成功轉換爲 子類指針;

      2)dynamic_cast 轉換:父類指針 不可以轉換爲  子類指針;

       

類型轉換函數

一、轉換構造函數

  當構造函數只有1個參數 參數的類型是基本類型 或者是 其它類型時,就是轉換構造函數。其做用是將其餘類型 轉換爲 類類型

  編譯器盡力嘗試的結果是隱式類型轉換,隱式類型轉換是工程中bug的重要來源;

  工程中經過explicit關鍵字杜絕隱式轉換,轉換構造函數被explicit修飾時只能進行顯示轉換;

  轉換方式

  1. static_ cast<ClassName >(value);

  2. ClassName(value);

  3. (ClassName)value; //不推薦

  在類型轉換時調用轉換構造函數。

         

 1 #include <iostream>
 2 #include <string>
 3 
 4 using namespace std;
 5 
 6 class Test
 7 {
 8     int mValue;
 9 public:
10     Test()
11     {
12         mValue = 0;
13     }
14     
15     explicit Test(int i)
16     {
17         mValue = i;
18     }
19     
20     Test operator + (const Test& p)
21     {
22         Test ret(mValue + p.mValue);
23         
24         return ret;
25     }
26     
27     int value()
28     {
29         return mValue;
30     }
31 };
32 
33 int main()
34 {   
35     Test t;
36     Test r;
37     
38     // 隱式類型轉換 不加explicit關鍵字
39     //t = 5;        // t = Test(5);
40     //r = t + 10;   // r = t + Test(10);
41     
42     t = static_cast<Test>(5);    // t = Test(5);    
43     r = t + static_cast<Test>(10);   // r = t + Test(10);
44     
45     cout << r.value() << endl;  // 15
46     
47     return 0;
48 }
轉換構造函數之 基本類型 -> 類類型

 二、類型轉換函數

   c++ 中能夠定義類型轉換函數,其做用是將 類類型 轉換爲 其它類型;其語法格式爲:

1 // 類型轉換函數語法格式
2 operator Type()
3 {
4      Type ret;
5 
6      // ...
7   
8      retuan Type;
9 }

  編譯器可以隱式的使用類型轉換函數

 

 1 #include <iostream>
 2 #include <string>
 3 
 4 using namespace std;
 5 
 6 class Test
 7 {
 8     int mValue;
 9 public:
10     Test(int i = 0)
11     {
12         mValue = i;
13     }
14     int value()
15     {
16         return mValue;
17     }
18     operator int ()
19     {
20         return mValue;
21     }
22 };
23 
24 int main()
25 {   
26     Test t(100);
27     int i = t;  // 隱式的使用類型轉換函數 operator int ()
28     
29     cout << "t.value() = " << t.value() << endl;    // t.value() = 100
30     cout << "i = " << i << endl;    // i = 100
31     
32     return 0;
33 }
類型轉換函數之 類類型 -> 基本類型

三、類型轉換函數  VS  轉換構造函數 

  結論:

  1. 類型轉換函數 與 轉換構造函數 具備同等的地位

  2. 沒法抑制隱式的類型轉換函數調用,此時 類型轉換函數可能與轉換構造函數衝突(類類型之間的轉換);

  3. 在類型轉換時 調用類型轉換函數 、轉換構造函數。

  4. 工程中以Type toType()的公有成員 代替 類型轉換函數

    

 1 #include <iostream>
 2 #include <string>
 3 
 4 using namespace std;
 5 
 6 class Test;
 7 
 8 class Value
 9 {
10 public:
11     Value()
12     {
13     }
14     explicit Value(Test& t)
15     {
16         cout << "explicit Value(Test& t)" << endl;
17     }
18 };
19 
20 class Test
21 {
22     int mValue;
23 public:
24     Test(int i = 0)
25     {
26         mValue = i;
27     }
28     int value()
29     {
30         return mValue;
31     }
32     operator Value()
33     {
34         Value ret;
35         cout << "operator Value()" << endl;
36         return ret;
37     }
38 };
39 
40 int main()
41 {   
42     Test t(100);
43     Value v1 = t;    // 隱式的調用類型轉換函數 operator Value()
44     Value v2 = static_cast<Value>(t);    // 顯示的調用轉換構造函數 explicit Value(Test& t)
45     
46     return 0;
47 }
48 /*
49     運行結果:
50     operator Value()
51     explicit Value(Test& t)
52 */
類類型之間的相互轉換

      //  類型轉換函數與轉換構造函數發生衝突   的示意圖    

           

相關文章
相關標籤/搜索