【c++】四種類型轉換形式
編譯時:
static_cast(靜態轉換)
const_cast(去常性轉換)
reinterpret_cast(重新解釋轉換,直接轉換地址)
運行時:
dynamic_cast(動態轉換,運行時類型識別 RTTI)
static_cast(靜態轉換)
用途 | 描述 | 注意事項 |
---|---|---|
基本數據類型之間的轉換 | 用于 int 轉 double 、char 轉 int 等類型之間的轉換。 | 適用于已知類型的轉換,比 C 風格轉換更安全。 |
void* 轉換為其他類型 | 用于將 void* 指針還原為具體類型的指針。 | 必須確保指針類型正確,避免未定義行為。 |
左值轉換為右值 | 用于將左值轉換為右值引用,常用于移動語義。 | 強制轉換為右值引用,觸發移動構造。 |
類型層次結構中的指針和引用轉換 | 在類繼承關系中,用于基類和派生類之間的轉換。 | 只能進行安全的向上轉換,向下轉換需要 dynamic_cast 。 |
int 類型轉換為枚舉 | 允許 int 與枚舉類型之間的轉換。 | 適用于整數到枚舉的安全轉換。 |
static_cast 在模板中的應用 | 用于確保目標類型和原始類型一致,并在模板編程中進行類型轉換。 | 使用 static_assert 進行編譯期類型檢查。 |
1. 基本數據類型轉換
static_cast
可用于基本數據類型之間的轉換,如 int
轉 double
、char
轉 int
,等價于 C 風格轉換,但更安全。
#include <iostream>int main() {double d = 3.14159;int i = static_cast<int>(d); // 截斷小數部分,轉換為 3char c = 'A';int ascii = static_cast<int>(c); // 將字符 'A' 轉換為 ASCII 碼std::cout << "i = " << i << ", ascii = " << ascii << std::endl;return 0;
}
? 優點:比 C 風格轉換更安全,可讀性更好,避免了 reinterpret_cast
的風險。
2. void*
轉換為其他類型
static_cast
可以用于將 void*
還原為具體類型,但必須確保指針類型正確,否則可能導致未定義行為。
#include <iostream>int main() {int a = 42;void* pVoid = &a; // int* → void*int* pInt = static_cast<int*>(pVoid); // void* → int*std::cout << "pInt = " << *pInt << std::endl;return 0;
}
? 適用于已知原始類型的情況,如果不確定類型,應使用 reinterpret_cast
。
3. 左值轉換為右值
在 C++11 及更高版本中,static_cast
可以將左值轉換為右值引用,用于移動語義。
#include <iostream>
#include <utility> // std::moveclass Data {
public:Data() { std::cout << "構造函數\n"; }Data(const Data&) { std::cout << "拷貝構造\n"; }Data(Data&&) { std::cout << "移動構造\n"; }
};int main() {Data d;Data d2 = static_cast<Data&&>(d); // 強制轉換為右值引用,觸發移動構造return 0;
}
? 與 std::move
類似,但 static_cast<Data&&>
是顯式的轉換方式。
4. 類型層次結構中的指針和引用轉換
在類的繼承關系中,static_cast
可以在基類和派生類之間進行轉換,但僅限安全的向上轉換。
#include <iostream>class Base {
public:virtual void show() { std::cout << "Base 類\n"; }
};class Derived : public Base {
public:void show() override { std::cout << "Derived 類\n"; }
};int main() {Derived d;Base* pBase = static_cast<Base*>(&d); // 向上轉換pBase->show(); // 仍然調用 Derived 的 `show()`return 0;
}
?? 向下轉換(Base*
→ Derived*
)是不安全的,需要用 dynamic_cast
。
5. int
類型轉換為枚舉
static_cast
允許整數和枚舉類型之間的轉換。
#include <iostream>enum Color { RED, GREEN, BLUE };int main() {int num = 1;Color c = static_cast<Color>(num); // 將 int 轉換為枚舉類型std::cout << "c = " << c << std::endl;return 0;
}
? 適用于整數到枚舉的安全轉換。
6. static_cast
在模板中的應用
在模板編程中,可以使用 static_cast
確保目標類型和原始類型一致。
#include <iostream>
#include <type_traits>template <typename T, typename U>
T convert(U value) {static_assert(std::is_convertible<U, T>::value, "類型不兼容!");return static_cast<T>(value);
}int main() {double d = 3.14;int i = convert<int>(d); // double → intstd::cout << "i = " << i << std::endl;return 0;
}
? static_assert
可用于編譯期檢查類型是否可以轉換。
const_cast(去常性轉換)
特點 | 描述 |
---|---|
只能對同類型使用 | const_cast 類型必須相同。 |
不能用于基本數據類型 | 不能用于基本數據類型之間的轉換(例如:int → double )。 |
轉換目標為指針或引用 | 只能將指針或引用的常量屬性去除,而不能作用于值類型。 |
常量指針/引用被轉換為非常量的指針/引用,并仍然指向原來的對象
例子:
-
常量指針轉為非常量指針
#include <iostream>void modifyValue(const int* ptr) {// const_cast 去常性轉換int* modifiablePtr = const_cast<int*>(ptr);*modifiablePtr = 20; // 可以修改原對象 }int main() {const int a = 10;modifyValue(&a); // 將常量指針轉換為非常量指針return 0; }
-
常量引用轉為非常量引用
#include <iostream>void modifyValue(const int& ref) {// const_cast 去常性轉換int& modifiableRef = const_cast<int&>(ref);modifiableRef = 20; // 可以修改原對象 }int main() {const int a = 10;modifyValue(a); // 將常量引用轉換為非常量引用return 0; }
注意事項:
const_cast
只會移除常量屬性,并不會改變對象本身。- 對于常量對象的修改仍然是未定義行為,因此不應使用
const_cast
去修改那些原本是常量的數據。
reinterpret_cast(重新解釋轉換)
是 C++ 中最危險的類型轉換之一,它將數據從一種類型“強制”轉換為另一種類型,并且不進行任何類型檢查。
它是按位解釋的
特點 | 描述 |
---|---|
最危險的轉換 | reinterpret_cast 不進行任何類型檢查,可能導致未定義行為。 |
按位解釋 | 轉換直接基于內存的二進制表示,不考慮類型的語義。 |
指針之間的轉換 | 可用于不同類型的指針之間的轉換。 |
指針與整數之間的轉換 | 可將指針轉換為整數,反之亦然。 |
1. 指針類型轉換
#include <iostream>int main() {int a = 42;// 強制將 int* 轉換為 double*,危險操作,按位解釋double* p = reinterpret_cast<double*>(&a);std::cout << *p << std::endl; // 不確定行為,可能崩潰return 0;
}
2. 指針與整數轉換
#include <iostream>int main() {int* p = reinterpret_cast<int*>(0x1234); // 將整數轉換為指針std::cout << "Pointer: " << p << std::endl;uintptr_t addr = reinterpret_cast<uintptr_t>(p); // 將指針轉換為整數std::cout << "Address as integer: " << addr << std::endl;return 0;
}
動態轉換(dynamic_cast
)
是一種用于在類層次結構中進行指針或引用類型轉換的操作,特別適用于下行轉換(基類指針或引用轉換為派生類指針或引用)。dynamic_cast
在運行時檢查類型安全,依賴于虛函數表和運行時類型信息(RTTI),通過虛函數表中的信息來實現類型檢查。
動態轉換的基本概念:
-
上行轉換(向上轉換):
- 向上轉換是指派生類對象轉換為基類指針或引用是在編譯時進行的,與靜態類型轉換等價,不查虛表
-
下行轉換(向下轉換):
- 向下轉換是指基類指針或引用轉換為派生類指針或引用。這種轉換在運行時需要類型檢查,
- 并且只有在公有繼承和繼承關系中存在虛函數時才有效,否則沒有運行時類型信息(RTTI)進行類型檢查。
- 使用
dynamic_cast
來進行下行轉換時,轉換成功時返回派生類指針或引用,轉換失敗時返回nullptr
(對于指針類型),或者拋出std::bad_cast
異常(對于引用類型)。 - 例如:
class Base { public:virtual ~Base() {} // 必須有虛析構函數,以支持RTTI };class Derived : public Base {};int main() {Base* pBase = new Derived();Derived* pDerived = dynamic_cast<Derived*>(pBase); // 成功,轉換為派生類指針if (pDerived) {std::cout << "轉換成功!" << std::endl;} else {std::cout << "轉換失敗!" << std::endl;}delete pBase;return 0; }
- 如果
pBase
實際上指向一個Derived
類型對象,則pDerived
會成功轉換,并指向該對象。 - 如果
pBase
并不指向Derived
類型對象,dynamic_cast
將返回nullptr
,指示轉換失敗。
- 如果
如何判斷是否能夠進行下行轉換:
- 條件:只有當類之間存在虛函數(如虛析構函數)時,RTTI 才會被啟用,
dynamic_cast
才能進行類型檢查。 - 執行流程:
dynamic_cast
會查詢對象的虛函數表(vtable)。- 如果查詢到類型匹配,則轉換成功。
- 如果查詢失敗,則返回
nullptr
(對于指針類型),或拋出異常std::bad_cast
(對于引用類型)。