1. 程式人生 > >【面試題】c++有哪四個型別轉換相關的關鍵字?

【面試題】c++有哪四個型別轉換相關的關鍵字?

在C/C++語言中用 (type) value(在C++還可以採用type(value))來進行顯式型別轉換(explicit type conversion),常常又被稱為強制轉換(cast投射/鑄模)。這種轉換的正確性完全掌握在程式設計師手中,傳統上強制轉換往往被過度使用,成為C++程式犯錯的一個主要根源。
為了減少強制轉換的副作用,並且在查錯時使程式設計師能夠快速定位(總是最值得懷疑的)強制轉換,在標準C++中新增加了4個關鍵字*_cast,用來提倡一種全新的C++顯式轉換語法:
*_cast <type-id> (expression)

1、reinterpret_cast<type-id> (expression)

type-id 必須是一個指標、引用、算術型別、函式指標或者成員指標。它可以把一個指標轉換成一個整數,也可以把一個整數轉換成一個指標(先把一個指標轉換成一個整數,再把該整數轉換成原型別的指標,還可以得到原先的指標值)。

static_cast和reinterpret_cast的區別主要在於多重繼承reinterpret_cast(重解釋轉換):一種最有可能出問題的最不安全的型別轉換。只是在下面的情形,才需要使用這種型別轉換:當需要使用時,所得到的東西已經不同了,為了使它能夠用於原來的目的,必須再次把它轉換回來。例如:

const int sz = 100; // 定義陣列大小,標準C++提倡用常型變數(而不是常數或
// 符號常量巨集)
struct X {int a[sz];}; // 只包含一個整數陣列的結構
X x; // 定義結構變數,此時結構中的陣列元素的值無意義(需要初始化)
int *px = reinterpret_cast<int *> (&x); // 為了初始化,先把結構轉化為int陣列
for (int *i = px; i < px + sz; i++) *i = 0; // 將每個陣列元素的值初始化為0
print(reinterpret_cast<X *> (px)); // 重新轉換成結構指標,以便使用
// 也可以直接使用原來的識別符號x
// 此語句相當於print(&x);
使用reinterpret_cast通常是一種不明智且不方便的程式設計方式。但是在必須使用時,它也是非常有用的。

2、static_cast<T*>(content)靜態轉換

主要用於c++中內建的基本資料型別之間的轉換,在編譯期間處理,但是沒有執行時型別的檢測來保證轉換的安全性

該運算子把expression轉換為type-id型別,但沒有執行時型別檢查來保證轉換的安全性。它主要有如下幾種用法:

用於類層次結構中基類(父類)和派生類(子類)之間指標或引用的轉換。

進行上行轉換(把派生類的指標或引用轉換成基類表示)是安全的;

進行下行轉換(把基類指標或引用轉換成派生類

表示)時,由於沒有動態型別檢查,所以是不安全的

②用於基本資料型別之間的轉換,如把int轉換成char,把int轉換成enum。這種轉換的安全性也要開發人員來保證。

③把空指標轉換成目標型別的空指標。

④把任何型別的表示式轉換成void型別。

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

C++primer第五章裡寫了編譯器隱式執行任何型別轉換都可由static_cast顯示完成; reinterpret_cast通常為運算元的位模式提供較低層的重新解釋

static_cast(靜態轉換):用於明確定義良性和適度良性的轉換,包括原來不需要採用強制轉換的自動型別轉換(包括無損的提升轉換和可能丟失資訊的窄化轉換[narrowing conversion],對後者編譯器一般會提出警告)。即將編譯器隱式執行的轉型弄成顯示的。標準C++提倡對任何資料的型別轉換(不論是自動的還是強制的),都採用新的*_cast顯式型別轉換方法。例如:

int i = 0x7fff;
long l;
float f;
char c;
// (1)典型的非強制轉換(自動轉換)
// 傳統方式:
l = i;
f = i;
// 提倡的新方式:
l = static_cast<long>(i);
f = static_cast<float>(i);
// (2)窄化轉換
// 傳統方式:
// 會顯示警告資訊:
i = l; // 可能丟失數字
i = f; // 可能丟失資訊
c = i; // 可能丟失數字
// 不顯示警告資訊(但仍然難定位):
i = (int)l;
i = (int)f;
c = (char)i;
// 提倡的新方式(不會顯示警告資訊,且易定位):
i = static_cast<int>(l);
i = static_cast<int>(f);
c = static_cast<char>(i);
3、dynamic_cast <type-id> (expression)

將一個基類物件指標(或引用)cast到繼承類指標,dynamic_cast會根據基類指標是否真正指向繼承類指標來做相應處理.

該運算子把expression轉換成type-id型別的物件。Type-id 必須是類的指標、類的引用或者void*; 如果 type-id 是類指標型別,那麼expression也必須是一個指標,如果 type-id 是一個引用,那麼 expression 也必須是一個引用。 dynamic_cast運算子可以在執行期決定真正的型別。如果 downcast 是安全的(也就說,如果基類指標或者引用確實指向一個派生類物件)這個運算子會傳回適當轉型過的指標。如果 downcast 不安全,這個運算子會傳回空指標(也就是說,基類指標或者引用沒有指向一個派生類物件)。 dynamic_cast主要用於類層次間的上行轉換和下行轉換,還可以用於類之間的交叉轉換。

dynamic_cast(動態轉換):一種安全的向下型別轉換(downcast)操作,用於在一個類繼承層次上向下移動。

因為每個派生類的基類都只有一個,而且派生類本身又包含了幾乎所有的基類資訊(private型的除外),所以向上的型別轉換(upcast)總是唯一的和比較安全的
而一個基類往往有多個派生類,而且派生類中一般會在基類的基礎上添加了一些特有的資料和操作,所以向下的型別轉換總是多型的和不太安全的
dynamic_cast提供了一種安全的向下型別轉換操作,只有當型別轉換是正確的並且轉換取的成功,返回值才是所需要的指標;否則它將返回0(空指標NULL),表示不是正確的型別。
例如:
class Pet {……};
class Dog : public Pet {……};
class Cat : public Pet {……};
……
Pet *pPet = new Cat; // 向上的型別轉換
Dog *pDog = dynamic_cast<Dog *>(pPet); // 型別錯誤,返回0(NULL)
Cat *pCat = dynamic_cast<Cat *>(pPet); // 型別正確,返回指標
Cat *pCat = static_cast<Cat *>(pPet); // 正確,減少執行時的開銷

注意:dynamic_cast雖然安全,但是執行時需要一定開銷,因此不提倡大量使用這種轉換。如果你已經能夠確認轉換的正確性,則可以採用前面介紹過的(無執行時開銷的)static_cast轉換。只有當你實在無法確定轉換是否正確時,才需要採用dynamic_cast轉換

在類層次間進行上行轉換時,dynamic_cast和static_cast的效果是一樣的;

4、const_cast

const_cast,用於修改型別的const或volatile屬性。

const_cast<type_id> (expression) 該運算子用來修改型別的const或volatile屬性。除了const 或volatile修飾之外, type_id和expression的型別是一樣的。 一、常量指標被轉化成非常量的指標,並且仍然指向原來的物件; 二、常量引用被轉換成非常量的引用,並且仍然指向原來的物件

三、const_cast一般用於修改底指標。如const char *p形式。

const_cast(常量轉換):可將(同資料型別的)常型(const)轉換為非常型、將易變(volatile)型轉換為非易變型。如果用於其他型別的轉換,一般會產生一個編譯錯誤。例如:

const int i = 0;
int *pi;
pi = &i; // 錯誤
pi = (int *)&i; // 被反對
pi = const_cast<int *>(&i); // 完美
long *pl = const_cast<long *>(&i); // 錯誤,要求是同資料型別
volatile int k = 0;
int *pk = const_cast<int *>(&k); // 正確

-----------------------------------------------------------------------------------------------------------------------------------------------------

在這四種強制轉換中,static_cast最常用(目前還沒有流行起來,但是被標準C++著力提倡)、dynamic_cast最重要、const_cast也有用、而reinterpret_cast則很少被使用。 


相關推薦

試題c++型別轉換相關關鍵字

在C/C++語言中用 (type) value(在C++還可以採用type(value))來進行顯式型別轉換(explicit type conversion),常常又被稱為強制轉換(cast投射/鑄模)。這種轉換的正確性完全掌握在程式設計師手中,傳統上強制轉換往往被過度使

試題Python高級開發工程師試題

http ges log com .com blog mage 回復 image 線上面試題,有空整理答案,歡迎大家回復答案 【面試題】Python高級開發工程師面試題

試題LRU算法及編碼實現LRU策略緩存

max 防止 技術分享 nbsp pri value 概念 閾值 使用 概念   LRU(least recently used)就是將最近不被訪問的數據給淘汰掉,LRU基於一種假設:認為最近使用過的數據將來被使用的概率也大,最近沒有被訪問的數據將來被使用的概率比較低。

試題2018年最全Java面試通關秘籍第五套!

XA 中文分詞 coo div rop 為什麽 3.2 自旋 FQ 【面試題】2018年最全Java面試通關秘籍第五套! 原創 2018-04-26 徐劉根 Java後端技術 第一套:《2018年最全Java面試通關秘籍第一套!》 第二套:《2018年最全Java面試通

試題Java試題--基礎總結--個人學習記錄

1、Java執行緒的狀態 新建new:新建立一個執行緒物件。 就緒runnable:建立執行緒物件後呼叫start方法,此時執行緒進入可執行狀態,等待CPU的時間片,且其他所需資源已獲得。 執行running(一般不考慮這種狀態):執行緒分得CPU的時間片、資源後執行執行緒。 阻塞b

試題Java試題--技術框架--個人學習記錄

1、看過哪些開源框架的原始碼   2、為什麼要用Redis,Redis有哪些優缺點?Redis如何實現擴容?   3、Netty是如何使用執行緒池的,為什麼這麼使用   4、為什麼要使用Spring,Spring的優缺點有哪些 &

試題Java試題--技術深度--個人學習記錄

1、有沒有看過JDK原始碼,看過的類實現原理是什麼。 2、HTTP協議   TCP詳解 關於http協議 3、TCP協議   TCP詳解 關於http協議 4、一致性Hash演算法 5、JVM如何載入位元組碼檔案 loa

試題Java 2(多)大整數相加如何實現

之前面試阿里的時候,第四面的時候面試官讓我當他面實現這個題目, 一開始的時候問的時候 2個相加如何實現,然後我寫完了之後又問我如果是多個相加呢?面試官希望我能在實現的時候能夠考慮到各種可能性,比如多個數相加,然後等我寫完了之後,又問我有沒有更好的實現方法;以下是我的實現方法; 將待相加

試題多執行緒在執行過程中,某個執行緒執行時,突然釋放鎖。會發生的特殊狀態

一,背景 今天在刷面試題的時候,做到一道面試題,雖然看了答案,但有一個答案還是不理解。後來研究了一下,得到結論:執行緒拿到鎖進行執行時,哪怕獲得了CPU執行權,但是那個鎖不能丟失,它後面執行的過程都需要帶著鎖,才能往下繼續執行。 二,測試程式碼 /**

試題同學的

汽車之家 1、訪問修飾符有哪幾種?有什麼的區別? 2、面向物件三大特性?在開發中怎麼體現? 3、redis有哪些資料型別? 4、資料庫索引瞭解過嗎? 5、spring mvc 一個請求的處理過程是怎麼樣的? 6、List有那些型別,內部由什麼構成? 7、從上一家公司離職的原因是什麼? 8、什麼時候能入職? 汽

試題求連結串列的環入口點

環入口點:我們設A是連結串列的起點,B是環的入口點,C是環內快慢指標的相遇點。兩個快慢指標定義為slow和fast. slow走的路程:A->B->C; fast走的路程:A->B->C->B->C; 2*(x+y)=x+y+z+y 

試題KMP演算法實現

what!? KMP演算法是幹嘛的? 我們可能都知道樸素演算法,主要是解決兩個字串的匹配問題,其實KMP演算法可以說和樸素演算法是師出同門,為什麼這麼講呢?首先我們對比一下兩個的程式碼,大家就知道怎麼回事了。 樸素演算法 int BF(const char *str1

試題佇列實現一個棧

題目:用佇列來實現棧。 用兩個佇列來回倒騰基本就可以了,假設有兩個佇列A、B,初始都為空,將元素放入佇列A中,如果佇列B不為空,將B中的元素全部取出放入A中,這樣B就為空隊列了,然後下次加入元素就加入

試題給多無序正整數,求中位數

題目:給你很多很多正整數,但它們是無序的,找出它們的中位數。 最開始就想說使用快排,先將這些整數進行排序,然後找到中位數,但又想到可能不是面試官想要的答案,於是又採用了其他方法,最終也沒完全解決出來。 【經驗總結:當面試官問了一個演算法題後,如果想不到優化一點的方法,就先

試題Java三大特性封裝繼承多型總結

本文內容總結於多篇部落格,參考到的地方在文中都會一一列出 http://www.cnblogs.com/ibalintha/p/3897821.html     1.封裝   封裝的定義: 首先是抽象,把事物抽象成一個類,其次才是封裝,

試題棋盤走法總數問題

題目:給定一個mxn的棋盤,每次只能向右或向下走,從左上角走到右下角,有多少中走法? 思路:可以使用動態規劃,狀態轉移方程為:dp[m][n]=dp[m-1][n]+dp[m][n-1],也可以使用遞

試題leetcode62:Unique Paths

瓜子面試題 思路:動態規劃求解即可。 程式碼: public class UniquePaths62 { public static void main(String[] args) {

試題資料庫索引及B樹、B+樹詳解

最近準備找一個實習,所以接下來,會通過其他人分享的面經陸續的總結面試中經常遇到的題 今天是關於資料庫索引,以及具體的實現(B樹及B+樹) 本文參考自兩篇部落格(個人認為是最好的相關部落格了) 資料庫索引部分:http://blog.csdn.net/weilianglian

試題JavaSE基礎常見面試題

基礎部分 1.Java語言的特性? 跨平臺性、面向物件、安全性、多執行緒、簡單易用。 2.& 和 && 的區別? &運算子表示按位與、邏輯與,而&&運算子是短路與運算。 3.String是最基本的資料

試題JVM相關

1.堆和棧的區別 棧記憶體是儲存方法幀和區域性變數(基本型別的變數、物件的引用變數),方法呼叫完後會釋放該棧及棧中變數。存取速度比堆要快,僅次於暫存器,棧資料可以共享,多個引用可以指向同一個地址,存