一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - C/C++ - C++ 強制類型轉換詳解

C++ 強制類型轉換詳解

2022-02-19 15:51zx255 C/C++

這篇文章主要介紹的是C++ 強制類型轉換詳解,C語言中的強制轉換主要用于普通數據類型、指針的強制轉換,沒有類型檢查,轉換不安全,下面我們來看看其具體語法及詳細內容

一、C強制轉換

C語言中的強制轉換主要用于普通數據類型、指針的強制轉換,沒有類型檢查,轉換不安全,

語法為:

?
1
2
(type-id)expression//轉換格式1
type-id(expression)//轉換格式2(基本已經不用了)

二、C++強制轉換

C++除了能使用c語言的強制類型轉換外,還新增了四種強制類型轉換:static_castdynamic_castconst_castreinterpret_cast

主要運用于繼承關系類間的強制轉化,語法為:

?
1
2
3
4
5
6
7
8
//靜態轉換
static_cast<new_type>      (expression)
//動態轉換
dynamic_cast<new_type>     (expression)
//常量轉換
const_cast<new_type>       (expression)
//重新解釋轉換
reinterpret_cast<new_type> (expression)

其中new type為轉換后的新類型,expression為舊類型

1、static_cast 靜態轉換(編譯時檢查)

用法:  static_cast <類型說明符> (變量或表達式)

static_cast靜態轉換相當于C語言中的強制轉換,但不能實現普通指針數據(空指針除外)的強制轉換,一般用于父類和子類指針、引用間的相互轉換。

用于類層次結構中基類(父類)和派生類(子類)之間 指針 或 引用 的轉換。不管是否發生多態,父子之間互轉時,編譯器都不會報錯。

  • (1)進行 上行轉換 (把派生類的指針或引用轉換成基類表示)是 安全 的;
  • (2)進行 下行轉換 (把基類指針或引用轉換成派生類表示)時,由于沒有動態類型檢查,所以是 不安全 的,但是編譯器不會報錯。

用于基本數據類型之間的轉換,如把int轉換成char,把int轉換成enum。這種轉換的安全性也要開發人員來保證。

把空指針轉換成目標類型的空指針。

把任何指針類型轉換成空指針類型。

注意:static_cast不能轉換掉expression的const、volatile、或者__unaligned屬性

如果涉及到類的話,static_cast只能在有相互聯系的類型中進行相互轉換,不一定包含虛函數。

在C++語言中static_cast用于數據類型的強制轉換,強制將一種數據類型轉換為另一種數據類型。例如將整型數據轉換為浮點型數據。

[例1]C語言所采用的類型轉換方式:

?
1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>
using namespace std;
 
int main() {
 int a = 10;
 int b = 3;
 double result = (double)a / (double)b;
 
 cout << result << endl; // 3.33333
 
 return 0;
}

例1中將整型變量a和b轉換為雙精度浮點型,然后相除。在C++語言中,我們可以采用static_cast關鍵字來進行強制類型轉換,如下所示。

[例2]static_cast關鍵字的使用:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>
using namespace std;
 
int main() {
 int a = 10;
 int b = 3;
 double result = static_cast<double> (a) / static_cast<double> (b);
 //其實寫一個 static_cast<double> 就行
 
 cout << result << endl; // 3.33333
 
 return 0;
}

在本例中同樣是將整型變量a轉換為雙精度浮點型。采用static_cast進行強制數據類型轉換時,將想要轉換成的數據類型放到尖括號中,將待轉換的變量或表達式放在元括號中。

2、const_cast 常量轉換

在C語言中,const限定符通常被用來限定變量,用于表示該變量的值不能被修改。

上邊的 static_cast 不能將 const int* 轉成 int* const_cast 就可以,

用法:  const_cast<type-i> (expression)

const_cast ,用于修改類型的constvolatile屬性,只能對是 引用 或者 指針 的變量添加或移除const。(除了const volatile修飾之外, type_idexpression的類型是一樣的。)

const_cast則正是用于強制去掉這種不能被修改的常數特性,但需要特別注意的是const_cast不是用于去除變量的常量性,而是去除 指向常數對象的指針或引用 的常量性,其去除常量性的對象必須為指針或引用。

  • 常量指針被轉化成非常量指針,并且仍然指向原來的對象;
  • 常量引用被轉換成非常量引用,并且仍然指向原來的對象;常量對象被轉換成非常量對象。
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
int main()
{
    const int a = 10;
    const int* p = &a;
    int* q = const_cast<int*>(p);
    *q = 20;    //fine
 
    cout << "a=" << a << " " << "&a = " << &a << endl;
    cout << "*p=" << *p << " " << "p = " << p << endl;
    cout << "*q=" << *q << " " << "q = " << q << endl;
 
    return 0;
}
 
//a = 10 & a = 012FFC10
//* p = 20 p = 012FFC10
//* q = 20 q = 012FFC10
 
int main() {
    int c = 11;
    const int a = c;
    const int* p = &a;
    int* q = const_cast<int*>(p);
    *q = 20;    //fine
 
    cout << "a=" << a << " " << "&a = " << &a << endl;
    cout << "*p=" << *p << " " << "p = " << p << endl;
    cout << "*q=" << *q << " " << "q = " << q << endl;
 
    return 0;
}
 
//a = 20 &a = 007BFD64
//* p = 20 p = 007BFD64
//* q = 20 q = 007BFD64
 
int main() {
    const int c = 11;
    const int a = c;
    const int* p = &a;
    int* q = const_cast<int*>(p);
    *q = 20;    //fine
 
    cout << "a=" << a << " " << "&a = " << &a << endl;
    cout << "*p=" << *p << " " << "p = " << p << endl;
    cout << "*q=" << *q << " " << "q = " << q << endl;
 
    return 0;
}
 
//a = 11 & a = 00EFFB44
//* p = 20 p = 00EFFB44
//* q = 20 q = 00EFFB44

查看運行結果,問題來了,指針p和指針q都是指向a變量的,指向地址相同,而且經過調試發現012FFC10地址內的值確實由10被修改成了20,這是怎么一回事呢?為什么a的值打印出來還是10呢?

其實這是一件好事,我們要慶幸a變量最終的值沒有變成20!變量a一開始就被聲明為一個常量變量,不管后面的程序怎么處理,它就是一個常量,就是不會變化的。試想一下如果這個變量a最終變成了20會有什么后果呢?對于這些簡短的程序而言,如果最后a變成了20,我們會一眼看出是q指針修改了,但是一旦一個項目工程非常龐大的時候,在程序某個地方出現了一個q這樣的指針,它可以修改常量a,這是一件很可怕的事情的,可以說是一個程序的漏洞,畢竟將變量a聲明為常量就是不希望修改它,如果后面能修改,這就太恐怖了。

我們稱“*q=20”語句為未定義行為語句,所謂的未定義行為是指在標準的C++規范中并沒有明確規定這種語句的具體行為,該語句的具體行為由編譯器來自行決定如何處理。對于這種未定義行為的語句我們應該盡量予以避免!

3、reinterpret_cast 重新解釋轉換

在C++語言中,reinterpret_cast 主要有三種強制轉換用途:

  • 改變指針或引用的類型
  • 將指針或引用轉換為一個足夠長度的整形
  • 將整型轉換為指針或引用類型

用法:  reinterpret_cast<type_id> (expression)

type-id必須是一個指針、引用、算術類型、函數指針或者成員指針。

它可以把一個指針轉換成一個整數,也可以把一個整數轉換成一個指針(先把一個指針轉換成一個整數,在把該整數轉換成原類型的指針,還可以得到原先的指針值)。

我們映射到的類型僅僅是為了故弄玄虛和其他目的,這是所有映射中最危險的。(這句話是C++編程思想中的原話)。因此, 你需要謹慎使用 reinterpret_cast

?
1
2
int *a = new int;
double *d = reinterpret_cast<double *>(a);

在上面代碼中,將整型指針通過reinterpret_cast強制轉換成了雙精度浮點型指針。
reinterpret_cast可以將指針或引用轉換為一個足夠長度的整形,此中的足夠長度具體長度需要多少則取決于操作系統,如果是32位的操作系統,就需要4個字節及以上的整型,如果是64位的操作系統則需要8個字節及以上的整型。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
typedef void (* FUNC)();
int DoSomething (int i)
{
    cout<< "DoSomething" <<endl;
 return 0;
}
 
void Test () {
 // reinterpret_cast可以編譯器以FUNC的定義方式去看待DoSomething函數
 // 所以非常的BUG,下面轉換函數指針的代碼是不可移植的,所以不建議這樣用
 // C++不保證所有的函數指針都被一樣的使用,所以這樣用有時會產生不確定的結果
 FUNC f = reinterpret_cast<FUNC>(DoSomething);
 f();
}

4、dynamic_cast 動態轉換(運行時檢查)

主要用于類層次結構中基類(父類)和派生類(子類)之間指針或引用的轉換(只能用于類間轉換,支持類間交叉轉換,不能操作普通數據。)

(1)在類的轉換時,在類層次間進行上行轉換時,dynamic_caststatic_cast的效果是一樣的。在進行下行轉換時,dynamic_cast具有類型檢查的功能,比static_cast更安全。

  • 向上轉換,即為子類指針指向父類指針(一般不會出問題);向下轉換,即將父類指針轉化子類指針。
  • 向下轉換的成功與否還與將要轉換的類型有關,即要轉換的指針指向的對象的實際類型與轉換以后的對象類型一定要相同,否則轉換失敗。
  • 在C++中,編譯期的類型轉換有可能會在運行時出現錯誤,特別是涉及到類對象的指針或引用操作時,更容易產生錯誤。Dynamic_cast操作符則可以在運行期對可能產生問題的類型轉換進行測試。

(2)發生多態時,允許互相轉換。
(3)無繼承關系的類之間也可以相互轉換,類之間的交叉轉換。
(4)如果dynamic_cast語句的轉換目標是指針類型并且失敗了,則結果為0。如果轉換目標是引用類型并且失敗了,則dynamic_cast運算符將拋出一個std::bad_cast異常
(5)使用 dynamic_cast 進行轉換的,基類中一定要有虛函數,否則編譯不通過(類中存在虛函數,就說明它有想要讓基類指針或引用指向派生類對象的情況,此時轉換才有意義)。這是由于運行時類型檢查需要運行時類型信息,而這個信息存儲在類的虛函數表中,只有定義了虛函數的類才有虛函數表。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class base {
public:
    void print1() { cout << "in class base" << endl; }
};
 
class derived : public base {
public:
    void print2() { cout << "in class derived" << endl; }
};
 
int main() {
    derived* p, * q;
    // p = new base; //  Compilr Error: 無法從 "base * " 轉換為 "derived * "
 
    // Compile Error: Cannot cast from 'base*' to 'derived*' via dynamic_cast: expression type is not polymorphic(多態的)
    // p = dynamic_cast<derived *>(new base);
 
    q = static_cast<derived*>(new base); // ok, but not recommended(推薦)
 
    q->print1(); // in class base
    q->print2(); // in class derived
    
    return 0;
}

從上邊的代碼可以看出用一個派生類的指針是不能直接指向一個基類的對象的,會出現編譯錯誤。用 dynamic_cast 的話也會編譯錯誤,提示我們基類不是多態的,也就是基類中沒有虛函數。可以看到 static_cast 是可以編譯通過的,且輸出結果看起來都是對的

static_cast 強制類型轉換時并不具有保證類型安全的功能,而 C++ 提供的 dynamic_cast 卻能解決這一問題,dynamic_cast 可以在程序運行時檢測類型轉換是否類型安全。當然 dynamic_cast 使用起來也是有條件的,它要求所轉換的 expression 必須包含多態類類型(即至少包含一個虛函數的類)。

三、要點總結

  • static_cast:在功能上基本上與C風格的類型轉換一樣強大,含義也一樣。它有功能上的限制。例如,你不能用static_cast像用C風格轉換一樣把struct轉換成int類型或者把double類型轉換成指針類型。另外,static_cast不能從表達式中去除const屬性,因為另一個新的類型轉換符const_cast有這樣的功能。可以靜態決議出類型的轉換可能性,即使是在繼承體系中,即使包括了多重繼承和虛繼承,只要可以進行靜態決議就可以轉換成功
  • const_cast:用于類型轉換掉表達式的constvolatile屬性。通過使用const_cast,你向人們和編譯器強調你通過類型轉換想做的只是改變一些東西的constness或者volatieness屬性。這個含義被編譯器所約束。如果你試圖使用const_cast來完成修改constness或者volatileness屬性之外的事情,你的類型轉換將被拒絕。
  • reinterpret_cast:使用這個操作符的類型轉換,其轉換結果幾乎都是執行期定義。因此,使用reinterpret_cast的代碼很難移植。reinterpret_casts的最普通的用途就是在函數指針類型之間進行轉換。
  • dynamic_cast:它被用于安全地沿著類的繼承關系向下進行類型轉換。這就是說,你能用dynamic_cast把指向基類的指針或引用轉換成指向其派生類或其兄弟類的指針或引用,而且你能知道轉換是否成功。失敗的轉換將返回空指針(當對指針進行類型轉換時)或者拋出異常(當對引用進行類型轉換時)。

C++ 強制類型轉換詳解

RTTI(Run-time Type identification)  :

通過運行時類型信息程序能夠使用 基類的指針或引用 來檢查這些指針或引用所指的對象的實際派生類型。(運行時類型識別)

(1)typeid操作符,返回指針和引用所指的實際類型:

可以判斷變量的類型,可以判斷兩個變量的類型是否相同,可以打印變量的類型(name())

比如:
typeid(a).name()就能知道變量a是什么類型

(2)dynamic_cast操作符,將基類類型的指針或引用安全地轉換為派生類型的指針或引用:

利用RTTI技術進行識別的父子類指針間轉化。會阻止原生的父類指針轉換為子類指針。阻止的方式是扔出一個bad_cast異常,且表達式的值變為NULL

到此這篇關于C/C++ 強制類型轉換詳解的文章就介紹到這了,更多相關C/C++ 強制類型轉換內容請搜索服務器之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持服務器之家!

注:文章轉自微信眾號:Coder梁(ID:Coder_LT)

原文鏈接:https://juejin.cn/post/7025799594030137357

延伸 · 閱讀

精彩推薦
  • C/C++深入理解goto語句的替代實現方式分析

    深入理解goto語句的替代實現方式分析

    本篇文章是對goto語句的替代實現方式進行了詳細的分析介紹,需要的朋友參考下...

    C語言教程網7342020-12-03
  • C/C++C語言實現電腦關機程序

    C語言實現電腦關機程序

    這篇文章主要為大家詳細介紹了C語言實現電腦關機程序,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下...

    xiaocaidayong8482021-08-20
  • C/C++學習C++編程的必備軟件

    學習C++編程的必備軟件

    本文給大家分享的是作者在學習使用C++進行編程的時候所用到的一些常用的軟件,這里推薦給大家...

    謝恩銘10102021-05-08
  • C/C++詳解c語言中的 strcpy和strncpy字符串函數使用

    詳解c語言中的 strcpy和strncpy字符串函數使用

    strcpy 和strcnpy函數是字符串復制函數。接下來通過本文給大家介紹c語言中的strcpy和strncpy字符串函數使用,感興趣的朋友跟隨小編要求看看吧...

    spring-go5642021-07-02
  • C/C++C++之重載 重定義與重寫用法詳解

    C++之重載 重定義與重寫用法詳解

    這篇文章主要介紹了C++之重載 重定義與重寫用法詳解,本篇文章通過簡要的案例,講解了該項技術的了解與使用,以下就是詳細內容,需要的朋友可以參考下...

    青山的青6062022-01-04
  • C/C++C語言中炫酷的文件操作實例詳解

    C語言中炫酷的文件操作實例詳解

    內存中的數據都是暫時的,當程序結束時,它們都將丟失,為了永久性的保存大量的數據,C語言提供了對文件的操作,這篇文章主要給大家介紹了關于C語言中文件...

    針眼_6702022-01-24
  • C/C++C/C++經典實例之模擬計算器示例代碼

    C/C++經典實例之模擬計算器示例代碼

    最近在看到的一個需求,本以為比較簡單,但花了不少時間,所以下面這篇文章主要給大家介紹了關于C/C++經典實例之模擬計算器的相關資料,文中通過示...

    jia150610152021-06-07
  • C/C++c++ 單線程實現同時監聽多個端口

    c++ 單線程實現同時監聽多個端口

    這篇文章主要介紹了c++ 單線程實現同時監聽多個端口的方法,幫助大家更好的理解和學習使用c++,感興趣的朋友可以了解下...

    源之緣11542021-10-27
主站蜘蛛池模板: 三级黄片毛片 | 国产精品www视频免费看 | 四虎永久在线精品国产 | 国产盗摄wc女厕所 | 万域之王动漫在线观看全集免费播放 | 校花被老头夺去第一次动图 | 17个农民工婉莹第一部 | 成人中文字幕在线观看 | 成年人免费在线看的惊悚动作片 | 视频一区二区国产无限在线观看 | jizz漫画| 国产a一级毛片午夜剧院 | 国产成人综合一区人人 | 四虎免费影院在线播放 | 九九精品影院 | 国产在线精品香蕉综合网一区 | 无人区1免费完整观看 | 欧美精品1区 | 国产123区 | 2021麻豆剧果冻传媒入口永久 | 久9青青cao精品视频在线 | 国产精品日韩欧美一区二区三区 | 无码乱人伦一区二区亚洲一 | 成年人黄色录像 | 欧美另类69xxx | 免费午夜网站 | 国产福利一区二区三区 | 视频一区二区三区在线 | 奇米影视在线视频8888 | 调教女帝 | 精精国产xxxx视频在线播放器 | 黄 色 成 年人在线 幻女free性俄罗斯第一次摘花 | 色一情| 办公室里被迫高h | 91天堂在线视频 | 亚洲天堂在线视频观看 | 久久伊人精品青青草原2021 | 图片专区亚洲欧美另类 | 日本中文字幕一区二区有码在线 | 美日韩一区二区三区 | 午夜亚洲福利 |