欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C++ 強制類型轉換詳解

 更新時間:2021年11月03日 10:47:30   作者:zx255  
這篇文章主要介紹的是C++ 強制類型轉換詳解,C語言中的強制轉換主要用于普通數(shù)據類型、指針的強制轉換,沒有類型檢查,轉換不安全,下面我們來看看其具體語法及詳細內容

一、C強制轉換

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

語法為:

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

二、C++強制轉換

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

#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關鍵字的使用:

#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進行強制數(shù)據類型轉換時,將想要轉換成的數(shù)據類型放到尖括號中,將待轉換的變量或表達式放在元括號中。

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則正是用于強制去掉這種不能被修改的常數(shù)特性,但需要特別注意的是const_cast不是用于去除變量的常量性,而是去除 指向常數(shù)對象的指針或引用 的常量性,其去除常量性的對象必須為指針或引用。

  • 常量指針被轉化成非常量指針,并且仍然指向原來的對象;
  • 常量引用被轉換成非常量引用,并且仍然指向原來的對象;常量對象被轉換成非常量對象。
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變量的,指向地址相同,而且經過調試發(fā)現(xiàn)012FFC10地址內的值確實由10被修改成了20,這是怎么一回事呢?為什么a的值打印出來還是10呢?

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

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

3、reinterpret_cast 重新解釋轉換

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

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

用法:  reinterpret_cast<type_id> (expression)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

三、要點總結

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

RTTI(Run-time Type identification)  :

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

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

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

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

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

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

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

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

相關文章

  • C/C++實現(xiàn)FTP文件上傳下載的示例詳解

    C/C++實現(xiàn)FTP文件上傳下載的示例詳解

    FTP(文件傳輸協(xié)議)是一種用于在網絡上傳輸文件的標準協(xié)議,這篇文章主要為大家詳細介紹了C++如何實現(xiàn)FTP文件上傳下載功能,需要的小伙伴可以參考下
    2023-12-12
  • C語言驅動開發(fā)之內核通過PEB獲取進程參數(shù)

    C語言驅動開發(fā)之內核通過PEB獲取進程參數(shù)

    PEB結構(Process Envirorment Block Structure)其中文名是進程環(huán)境塊信息。本文將通過PEB實現(xiàn)獲取進程參數(shù),感興趣的小伙伴可以了解一下
    2022-10-10
  • C++17?Filesystem?實用教程

    C++17?Filesystem?實用教程

    C++17的std::filesystem庫提供了強大的文件系統(tǒng)操作工具,本文就來介紹一下C++17?Filesystem?實用教程,具有一定的參考價值,感興趣的可以了解一下
    2025-01-01
  • C利用語言實現(xiàn)數(shù)據結構之隊列

    C利用語言實現(xiàn)數(shù)據結構之隊列

    隊列 (Queue):簡稱隊,是另一種限定性的線性表,它只允許在表的一端插入元素,而在另一端刪除元素。q=(a1, a2, a3, … an),其中a1為隊頭,an為隊尾,下面文章小編將為大家詳細介紹,需要的下伙伴可以參考一下
    2021-10-10
  • C++實現(xiàn)二叉樹的堂兄弟節(jié)點查詢

    C++實現(xiàn)二叉樹的堂兄弟節(jié)點查詢

    C++實現(xiàn)二叉樹的堂兄弟節(jié)點查詢,是指在二叉樹中,找到兩個節(jié)點深度相同但父節(jié)點不同的節(jié)點,即為堂兄弟節(jié)點。實現(xiàn)這一功能可以通過遍歷二叉樹并記錄節(jié)點深度和父節(jié)點來實現(xiàn)
    2023-04-04
  • 詳解C++中的左值,純右值和將亡值

    詳解C++中的左值,純右值和將亡值

    C++中本身是存在左值,右值的概念,但是在C11中又出現(xiàn)了左值,純右值,將亡值得概念;這里我們主要介紹這些值的概念,感興趣的可以了解一下
    2022-09-09
  • C語言實現(xiàn)鏈隊列代碼

    C語言實現(xiàn)鏈隊列代碼

    這篇文章主要為大家詳細介紹了C語言實現(xiàn)鏈隊列代碼,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-07-07
  • C++去除輸入行中空白的方法

    C++去除輸入行中空白的方法

    這篇文章主要介紹了C++去除輸入行中空白的方法,涉及C++針對數(shù)組的遍歷與替換的相關使用技巧,需要的朋友可以參考下
    2015-07-07
  • C語言內存泄露很嚴重的解決方案

    C語言內存泄露很嚴重的解決方案

    這篇文章主要介紹了C語言內存泄露很嚴重的解決方案,預防內存泄漏問題有多種方法,比如加強代碼檢視、工具檢測和內存測試等,下面文章總結內容需要的小伙伴可以參考一下
    2022-05-05
  • 基于QT實現(xiàn)文件上傳和下載功能

    基于QT實現(xiàn)文件上傳和下載功能

    這篇文章主要為大家詳細介紹了基于QT實現(xiàn)文件上傳和下載功能,支持斷點續(xù)傳,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-08-08

最新評論