c++中的類型轉換

来源:https://www.cnblogs.com/nbk-zyc/archive/2020/03/01/12383810.html
-Advertisement-
Play Games

目錄 1. 隱式類型轉換 2. 顯示類型轉換/強制類型轉換( static_cast、const_cast、reinterpret_cast、dynamic_cast) 3. 類型轉換函數、轉換構造函數 類型轉換可分為 隱式類型轉換(編譯器自動完成) 與 顯示類型轉換(強制類型轉換,需要自己操作)。 ...


目錄

  1. 隱式類型轉換

  2. 顯示類型轉換/強制類型轉換( static_castconst_castreinterpret_castdynamic_cast

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

 

  類型轉換可分為 隱式類型轉換(編譯器自動完成) 與 顯示類型轉換(強制類型轉換,需要自己操作)。

隱式類型轉換  

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

  

   我們用 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++中,還有其它幾種隱式類型轉換(後續講解),那麼現在試想一下這幾個問題:

    1. 基本類型 可以轉換為 類類型嗎?--- 可以,見轉換構造函數;

    2. 類類型 可以轉換為 基本類型嗎?--- 可以,見類型轉換函數;

    3. 類類型之間可以轉換嗎?--- 可以,見轉換構造函數 和 類型轉換函數;

  註:這種隱式類型轉換不能夠抑制,並且也是bug的來源之一;

顯示類型轉換/強制類型轉

  在介紹c++強制類型轉換前,我們可以回顧一下c語言中的強制類型轉換。c語言中的強制類型轉換十分簡單、粗暴,即 (Type)(Expression);或者 Type(Expression);但是,這種簡單的強制類型轉換引發了很多問題,可歸納為如下2點:

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

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

所以,基於這2點考慮,在c++中引入了新式類型轉換( static_castconst_castreinterpret_castdynamic_cast),其使用方法可歸納為 xxx_cast<Type>(Expression)

1、static_cast

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

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

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

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

2、 const_cast

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

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

3、 reinterpret_cast

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

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

4、 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、轉換構造函數

  當構造函數只有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 }
轉換構造函數之 基本類型 -> 類類型

 2、類型轉換函數

   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 }
類型轉換函數之 類類型 -> 基本類型

3、類型轉換函數  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 */
類類型之間的相互轉換

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

           

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一、Map常用方法簡介 package com.bjpowernode.java_learning; ​ import java.util.HashMap; import java.util.*; ​ public class D91_1_MapCommonMethod { public stati ...
  • 模型評價是指對於已經建立的一個或多個模型,根據其模型的類別,使用不同的指標評價其性能優劣的過程。常用的聚類模型評價指標有ARI評價法(蘭德繫數)、AMI評價法(互信息)、V-measure評分、FMI評價法和輪廓繫數等。常用的分類模型評價指標有準確率(Accuracy)、精確率(Precision) ...
  • 員工管理系統 因為學業要求,需要完成一個過關檢測,但是因為檢測之前沒有做好準備,且想到之前用mysql+jdbc+Struts2+bootstrap做成了一個ATM系統(主要有對數據的增刪改查操作),應對這次的檢測應該不成問題,但是萬萬沒想到,過關檢測重在“檢測”,需要在規定的時間內完成一個系統,且 ...
  • Python 程式能用很多方式處理日期和時間,轉換日期格式是一個常見的功能。Python 提供了 time ,datatime, calendar 等模塊可以用於格式化日期和時間。時間間隔是以秒為單位的浮點小數。每個時間戳都以自從 1970 年 1 月 1 日午夜(歷元)經過了多長時間來表示。Pyt ...
  • 本文章將要介紹的內容有以下幾點,讀者朋友也可先自行思考一下相關問題: 1. 線程中斷 interrupt 方法怎麼理解,意思就是線程中斷了嗎?那當前線程還能繼續執行嗎? 2. 判斷線程是否中斷的方法有幾個,它們之間有什麼區別? 3. LockSupport的 park/unpark 和 wait/n ...
  • defer 關鍵字 首先來看官網的定義: A "defer" statement invokes a function whose execution is deferred to the moment the surrounding function returns, either because ...
  • 1、運算符 運算符 功能 是否支持 字元串 列表 元組 字典 集合 + 合併 √ √ √ * 複製 √ √ √ in 判斷是否存在 √ √ √ √ √ not in 判斷是否不存在 √ √ √ √ √ 2、公共方法 len() 統計容器中元素的個數 del/del() 刪除 max() 返回容器中元 ...
  • 春節期間熟悉了TP6, 也寫了一個TP6的博客程式,但系統的異常頁面實在另外頭疼,很多時候無法查看到是哪行代碼出的問題。 所以就特別的想把whoops引進來,經過一系列的研究,終於找到瞭解決的辦法: 1. 通過composer安裝whoops 運行命令: composer require filp/ ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...