c++ 強制類型轉換


前言

在c語言中學的強制轉換是用()來實現的; 而在c++中更多的是用case-name系列的關鍵字來告訴編譯器我們需要轉換的類型. c++引入這些關鍵字也是為了看代碼的時候清晰明了, 每個關鍵字都有指定的功能. 下面我們就來分析這些關鍵字.

case-name關鍵字

1. static_cast

在編譯期間完成類型轉換.

a. 將原有的自動類型轉換 , 如 : short轉為int, int轉為double, 非const轉為const類型

short sh;
int i = static_cast<int>(sh);
const int ci = static_cast<const int>(i);

**b. void 指針和具體類型指針之間的轉換 **

void *vp;
int *ip = static_cast<int*>(vp);

c. 有轉換構造函數或者類型轉換函數的類與其它類型之間的轉換

如 : A是B的基類

B *b;
A *a = static_cast<A *>(b);	// 這種建議使用dynamic_cast來轉換

不能用於無關類型之間的轉換 , 如 : int* 轉為double* 等

int *pi;
double *di = static_cast<double *>(pi); // error

2. const_cast

const_cast (常用於函數的重載) 常量指針(引用)被轉化成非常量指針(引用),並且仍然指向原來的對象

顧名思義, const_cast就是在我們需要修改const修飾的常量的時候用.

const int ci = 1;
int *p = const_cast<int*>(&ci);
*p = 10;

cout << &ci << " " << p << endl;	// 0x7ffd856729cc 0x7ffd856729cc
cout << ci << endl;	// 1
cout << *p << endl;	// 10

注意 : 上面的ci的值最終還是沒有被修改, 這就是后半句 : 仍然指向原來的對象. 我們只能通過const_cast忽略對象的屬性, 卻依然不能修改對象.

可能有人就認為const_cast並沒有用, 但是我們確實用int*指向了const int*了, 這是一般我們都無法做到的. 同樣, 下面還有const_cast能夠做到的.

這有一部分的代碼, 我們在重載const函數時, 常常會重復寫很多一樣的代碼, 而使用const_cast就可以避免寫重復的代碼.

class A
{
public:
    ...
	const type& operator[](std::size_t size) const
	{
		return *(ar + size);
	}
	type& operator[](std::size_t size)
	{
		return const_cast<type &>(static_cast<const A&>(*this)[size]);
	}

private:
	...
	std::size_t size;
	type * ar;
};

3. reinterpret_cast

reinterpret_cast 這種轉換僅僅是對二進制位的重新解釋(修改), 不會借助已有的轉換規則對數據進行調整, 非常簡單粗暴, 風險很高, 一般我們不推薦使用.

但是既然c++規定了這中轉換, 那么什么時候用合適?在IBM C++指南中明確說了

  • 從指針類型到一個足夠大的整數類型
  • 從整數類型或者枚舉類型到指針類型
  • 從一個指向函數的指針到另一個不同類型的指向函數的指針
  • 從一個指向對象的指針到另一個不同類型的指向對象的指針
  • 從一個指向類函數成員的指針到另一個指向不同類型的函數成員的指針
  • 從一個指向類數據成員的指針到另一個指向不同類型的數據成員的指針

總結來說:reinterpret_cast用在任意指針(或引用)類型之間的轉換;以及指針與足夠大的整數類型之間的轉換;從整數類型(包括枚舉類型)到指針類型,無視大小

就像下面這樣static_cast無法做的但reinterpret_cast就可以完成, 但是賦值等操作卻會運行時報錯, 這就是reinterpret_cast不安全之處, 它能讓代碼通過編譯, 操作時卻會報錯, 一般建議reinterpret_cast只有將轉換后的類型值轉換回到其原始類型來使用, 做一個中間臨時轉存。

int *pi = NULL;
double *di = reinterpret_cast<double *>(pi);

4. dynamic_cast

dynamic_cast用於在類的繼承層次之間進行類型轉換, 它既允許向上轉型, 也允許向下轉型.

class A {};
class B : public A {};

向上轉型 : 基類指針(引用)指向子類指針(引用), 這樣的轉換是安全的.

B *b;
A *a = static_cast<A *>(b);	
A *ta = dynamic_cast<A *>(b);// 也可寫成這樣, 最好建議這樣轉換

向下轉型 : 借助 RTTI 信息進行檢測, 確定安全的才能轉換成功, 否則就轉換失敗, 有風險.

A *a;
B *b = dynamic_cast<B *>(a);

總結

雖然c語言的()強制能用, 但是最好推薦使用c++的轉化系列, 畢竟看代碼的時候很容易能夠知道轉化對象和原因, 也容易分析. 本片我將四種轉化盡量寫的簡單, 多用實例證明, 只是希望能夠快速的明了每個的用法.

  1. static_cast : 有關聯的 對象之間能夠進行轉化.
  2. const_cast : 忽略const/volatile修飾, 但是實際不會修改對象, 常用於重載
  3. dynamic_cast : 最多用於向下轉化, 但並不安全
  4. reinterpret_cast : 二進制間, 可無關聯對象間的轉化, 非常不安全.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM