溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

C++如何強(qiáng)制類型轉(zhuǎn)換

發(fā)布時(shí)間:2021-11-02 15:41:48 來源:億速云 閱讀:188 作者:小新 欄目:開發(fā)技術(shù)

小編給大家分享一下C++如何強(qiáng)制類型轉(zhuǎn)換,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!

一、C強(qiáng)制轉(zhuǎn)換

C語言中的強(qiáng)制轉(zhuǎn)換主要用于普通數(shù)據(jù)類型、指針的強(qiáng)制轉(zhuǎn)換,沒有類型檢查,轉(zhuǎn)換不安全,

語法為:

(type-id)expression//轉(zhuǎn)換格式1
type-id(expression)//轉(zhuǎn)換格式2(基本已經(jīng)不用了)

二、C++強(qiáng)制轉(zhuǎn)換

C++除了能使用c語言的強(qiáng)制類型轉(zhuǎn)換外,還新增了四種強(qiáng)制類型轉(zhuǎn)換:static_castdynamic_cast、const_castreinterpret_cast,

主要運(yùn)用于繼承關(guān)系類間的強(qiáng)制轉(zhuǎn)化,語法為:

//靜態(tài)轉(zhuǎn)換
static_cast<new_type>      (expression)
//動(dòng)態(tài)轉(zhuǎn)換
dynamic_cast<new_type>     (expression) 
//常量轉(zhuǎn)換
const_cast<new_type>       (expression) 
//重新解釋轉(zhuǎn)換
reinterpret_cast<new_type> (expression)

其中new type為轉(zhuǎn)換后的新類型,expression為舊類型

1、static_cast 靜態(tài)轉(zhuǎn)換(編譯時(shí)檢查)

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

static_cast靜態(tài)轉(zhuǎn)換相當(dāng)于C語言中的強(qiáng)制轉(zhuǎn)換,但不能實(shí)現(xiàn)普通指針數(shù)據(jù)(空指針除外)的強(qiáng)制轉(zhuǎn)換,一般用于父類和子類指針、引用間的相互轉(zhuǎn)換。

用于類層次結(jié)構(gòu)中基類(父類)和派生類(子類)之間 指針 或 引用 的轉(zhuǎn)換。不管是否發(fā)生多態(tài),父子之間互轉(zhuǎn)時(shí),編譯器都不會(huì)報(bào)錯(cuò)。

  • (1)進(jìn)行 上行轉(zhuǎn)換 (把派生類的指針或引用轉(zhuǎn)換成基類表示)是 安全 的;

  • (2)進(jìn)行 下行轉(zhuǎn)換 (把基類指針或引用轉(zhuǎn)換成派生類表示)時(shí),由于沒有動(dòng)態(tài)類型檢查,所以是 不安全 的,但是編譯器不會(huì)報(bào)錯(cuò)。

用于基本數(shù)據(jù)類型之間的轉(zhuǎn)換,如把int轉(zhuǎn)換成char,把int轉(zhuǎn)換成enum。這種轉(zhuǎn)換的安全性也要開發(fā)人員來保證。

把空指針轉(zhuǎn)換成目標(biāo)類型的空指針。

把任何指針類型轉(zhuǎn)換成空指針類型。

注意:static_cast不能轉(zhuǎn)換掉expression的const、volatile、或者_(dá)_unaligned屬性

如果涉及到類的話,static_cast只能在有相互聯(lián)系的類型中進(jìn)行相互轉(zhuǎn)換,不一定包含虛函數(shù)。

在C++語言中static_cast用于數(shù)據(jù)類型的強(qiáng)制轉(zhuǎn)換,強(qiáng)制將一種數(shù)據(jù)類型轉(zhuǎn)換為另一種數(shù)據(jù)類型。例如將整型數(shù)據(jù)轉(zhuǎn)換為浮點(diǎn)型數(shù)據(jù)。

[例1]C語言所采用的類型轉(zhuǎn)換方式:

#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轉(zhuǎn)換為雙精度浮點(diǎn)型,然后相除。在C++語言中,我們可以采用static_cast關(guān)鍵字來進(jìn)行強(qiáng)制類型轉(zhuǎn)換,如下所示。

[例2]static_cast關(guān)鍵字的使用:

#include <iostream>
using namespace std;

int main() {
 int a = 10;
 int b = 3;
 double result = static_cast<double> (a) / static_cast<double> (b);
 //其實(shí)寫一個(gè) static_cast<double> 就行
 
 cout << result << endl; // 3.33333

 return 0;
}

在本例中同樣是將整型變量a轉(zhuǎn)換為雙精度浮點(diǎn)型。采用static_cast進(jìn)行強(qiáng)制數(shù)據(jù)類型轉(zhuǎn)換時(shí),將想要轉(zhuǎn)換成的數(shù)據(jù)類型放到尖括號(hào)中,將待轉(zhuǎn)換的變量或表達(dá)式放在元括號(hào)中。

2、const_cast 常量轉(zhuǎn)換

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

上邊的 static_cast 不能將 const int* 轉(zhuǎn)成 int* ,const_cast 就可以,

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

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

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

  • 常量指針被轉(zhuǎn)化成非常量指針,并且仍然指向原來的對(duì)象;

  • 常量引用被轉(zhuǎn)換成非常量引用,并且仍然指向原來的對(duì)象;常量對(duì)象被轉(zhuǎn)換成非常量對(duì)象。

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

查看運(yùn)行結(jié)果,問題來了,指針p和指針q都是指向a變量的,指向地址相同,而且經(jīng)過調(diào)試發(fā)現(xiàn)012FFC10地址內(nèi)的值確實(shí)由10被修改成了20,這是怎么一回事呢?為什么a的值打印出來還是10呢?

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

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

3、reinterpret_cast 重新解釋轉(zhuǎn)換

在C++語言中,reinterpret_cast 主要有三種強(qiáng)制轉(zhuǎn)換用途:

  • 改變指針或引用的類型

  • 將指針或引用轉(zhuǎn)換為一個(gè)足夠長度的整形

  • 將整型轉(zhuǎn)換為指針或引用類型

用法:  reinterpret_cast<type_id> (expression)

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

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

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

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

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

typedef void (* FUNC)();
int DoSomething (int i)
{
    cout<< "DoSomething" <<endl;
 return 0; 
}

void Test () {
 // reinterpret_cast可以編譯器以FUNC的定義方式去看待DoSomething函數(shù)
 // 所以非常的BUG,下面轉(zhuǎn)換函數(shù)指針的代碼是不可移植的,所以不建議這樣用
 // C++不保證所有的函數(shù)指針都被一樣的使用,所以這樣用有時(shí)會(huì)產(chǎn)生不確定的結(jié)果 
 FUNC f = reinterpret_cast<FUNC>(DoSomething);
 f();
}

4、dynamic_cast 動(dòng)態(tài)轉(zhuǎn)換(運(yùn)行時(shí)檢查)

主要用于類層次結(jié)構(gòu)中基類(父類)和派生類(子類)之間指針或引用的轉(zhuǎn)換(只能用于類間轉(zhuǎn)換,支持類間交叉轉(zhuǎn)換,不能操作普通數(shù)據(jù)。)

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

  • 向上轉(zhuǎn)換,即為子類指針指向父類指針(一般不會(huì)出問題);向下轉(zhuǎn)換,即將父類指針轉(zhuǎn)化子類指針。

  • 向下轉(zhuǎn)換的成功與否還與將要轉(zhuǎn)換的類型有關(guān),即要轉(zhuǎn)換的指針指向的對(duì)象的實(shí)際類型與轉(zhuǎn)換以后的對(duì)象類型一定要相同,否則轉(zhuǎn)換失敗。

  • 在C++中,編譯期的類型轉(zhuǎn)換有可能會(huì)在運(yùn)行時(shí)出現(xiàn)錯(cuò)誤,特別是涉及到類對(duì)象的指針或引用操作時(shí),更容易產(chǎn)生錯(cuò)誤。Dynamic_cast操作符則可以在運(yùn)行期對(duì)可能產(chǎn)生問題的類型轉(zhuǎn)換進(jìn)行測試。

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

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 * " 轉(zhuǎn)換為 "derived * "

    // Compile Error: Cannot cast from 'base*' to 'derived*' via dynamic_cast: expression type is not polymorphic(多態(tài)的)
    // 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;
}

從上邊的代碼可以看出用一個(gè)派生類的指針是不能直接指向一個(gè)基類的對(duì)象的,會(huì)出現(xiàn)編譯錯(cuò)誤。用 dynamic_cast 的話也會(huì)編譯錯(cuò)誤,提示我們基類不是多態(tài)的,也就是基類中沒有虛函數(shù)??梢钥吹?static_cast 是可以編譯通過的,且輸出結(jié)果看起來都是對(duì)的

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

三、要點(diǎn)總結(jié)

  • static_cast:在功能上基本上與C風(fēng)格的類型轉(zhuǎn)換一樣強(qiáng)大,含義也一樣。它有功能上的限制。例如,你不能用static_cast像用C風(fēng)格轉(zhuǎn)換一樣把struct轉(zhuǎn)換成int類型或者把double類型轉(zhuǎn)換成指針類型。另外,static_cast不能從表達(dá)式中去除const屬性,因?yàn)榱硪粋€(gè)新的類型轉(zhuǎn)換符const_cast有這樣的功能??梢造o態(tài)決議出類型的轉(zhuǎn)換可能性,即使是在繼承體系中,即使包括了多重繼承和虛繼承,只要可以進(jìn)行靜態(tài)決議就可以轉(zhuǎn)換成功

  • const_cast:用于類型轉(zhuǎn)換掉表達(dá)式的constvolatile屬性。通過使用const_cast,你向人們和編譯器強(qiáng)調(diào)你通過類型轉(zhuǎn)換想做的只是改變一些東西的constness或者volatieness屬性。這個(gè)含義被編譯器所約束。如果你試圖使用const_cast來完成修改constness或者volatileness屬性之外的事情,你的類型轉(zhuǎn)換將被拒絕。

  • reinterpret_cast:使用這個(gè)操作符的類型轉(zhuǎn)換,其轉(zhuǎn)換結(jié)果幾乎都是執(zhí)行期定義。因此,使用reinterpret_cast的代碼很難移植。reinterpret_casts的最普通的用途就是在函數(shù)指針類型之間進(jìn)行轉(zhuǎn)換。

  • dynamic_cast:它被用于安全地沿著類的繼承關(guān)系向下進(jìn)行類型轉(zhuǎn)換。這就是說,你能用dynamic_cast把指向基類的指針或引用轉(zhuǎn)換成指向其派生類或其兄弟類的指針或引用,而且你能知道轉(zhuǎn)換是否成功。失敗的轉(zhuǎn)換將返回空指針(當(dāng)對(duì)指針進(jìn)行類型轉(zhuǎn)換時(shí))或者拋出異常(當(dāng)對(duì)引用進(jìn)行類型轉(zhuǎn)換時(shí))。

C++如何強(qiáng)制類型轉(zhuǎn)換

RTTI(Run-time Type identification)  :

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

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

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

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

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

利用RTTI技術(shù)進(jìn)行識(shí)別的父子類指針間轉(zhuǎn)化。會(huì)阻止原生的父類指針轉(zhuǎn)換為子類指針。阻止的方式是扔出一個(gè)bad_cast異常,且表達(dá)式的值變?yōu)?code>NULL。

以上是“C++如何強(qiáng)制類型轉(zhuǎn)換”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對(duì)大家有所幫助,如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

c++
AI