static_cast 靜態轉換
- 用于類層次結構中基類和派生類之間指針或者引用的轉換。up-casting (把派生類的指針或引用轉換成基類的指針或者引用表示)是安全的;down-casting(把基類指針或引用轉換成子類的指針或者引用)是不安全的。
- 用于基本數據類型之間的轉換,如把int轉換成char,這種轉換的安全性也要由開發人員來保證。
- 可以把空指針轉換成目標類型的空指針(null pointer)。
- 把任何類型的表達式轉換成void類型。
- 注意: static_cast不能轉換掉expression的const、volitale或者__unaligned屬性。
基本類型轉換:
#include <iostream>int main()
{int b = 20;float ft = 30.25f;b = static_cast<float>(ft);std::cout << "After static_cast b: " << b << std::endl;std::cout << "Finished! \n";return 0;
}
類的基本轉換:
#include <iostream>class Base
{
public:Base(int data):_data(data){}void printData(){std::cout << "Base data: " << _data << std::endl;}private:int _data;
};class TestA : public Base
{
public:TestA(int num, int data): _num(num), Base(data){}void printData(){std::cout << "TestA Num: " << _num << std::endl;}private:int _num;
};int main()
{Base base{ 10 };TestA testA{ 10,20 };// 向上轉換Base* base_ptr = static_cast<Base*>(&testA);base_ptr->printData();// 向下轉換:危險行為TestA* test_ptr = static_cast<TestA*>(&base);test_ptr->printData();std::cout << "Finished! \n";return 0;
}
觀察,向上轉換正常,向下轉換數據未定義。
dynamic_cast
typeid必須是類的指針、類的引用或者void*。如果typeid是類的指針類型,那么expression也必須是指針,如果typeid是一個引用,那么expression也必須是一個引用。一般情況下,dynamic_cast用于具有多態性的類(即有虛函數的類)的類型轉換。
dynamic_cast依賴于RTTI信息,其次,在轉換時,dynamic_cast會檢查轉換的source對象是否真的可以轉換成target類型,這種檢查不是語法上的,而是真實情況的檢查。先看RTTI相關部分,通常,許多編譯器都是通過vtable找到對象的RTTI信息的,這也就意味著,如果基類沒有虛方法,也就無法判斷一個基類指針變量所指對象的真實類型,這時候,dynamic_cast只能用來做安全的轉換,例如從派生類指針轉換成基類指針。而這種轉換其實并不需要dynamic_cast參與。也就是說,dynamic_cast是根據RTTI記載的信息來判斷類型轉換是否合法的。
-
主要用于類層次之間的up-casting和down-casting,還可以用于類之間的交叉轉換。在進行down-casting時,dynamic_cast具有類型檢查的功能,比static_cast更安全。檢測在運行時進行。如果被轉換的指針不是一個被請求的有效完整的對象指針,返回值為NULL。當用于多態類型時,它允許任意的隱式類型轉換以及相反過程。不過,與static_cast不同,在后一種情況里(注:即隱式轉 換的相反過程),dynamic_cast會檢查操作是否有效。也就是說,它會檢查轉換是否會返回一個被請求的有效的完整對象。
-
注意:dynamic_cast不能轉換掉expression的const、volitale或者__unaligned屬性。
測試,加入現在的基類沒有定義虛函數:
class Base
{
public:Base(int data):_data(data){}void printData(){std::cout << "Base data: " << _data << std::endl;}private:int _data;
};class TestA : public Base
{
public:TestA(int num, int data): _num(num), Base(data){}void printData(){std::cout << "TestA Num: " << _num << std::endl;}private:int _num;
};int main()
{Base* base_ptr = new Base(10);TestA* test_ptr = new TestA(10,20);Base* ptr_01 = dynamic_cast<Base*>(test_ptr);ptr_01->printData(); // ok#if 0TestA* ptr_02 = dynamic_cast<TestA*>(base_ptr); // errorptr_02->printData();
#endifstd::cout << "Finished! \n";return 0;
}
重新定義并測試:
class VirtualBase
{
private:int _data;public:VirtualBase(int data): _data(data){}virtual ~VirtualBase(){}virtual void printData(){std::cout << "Virtual Base. Data: " << _data << std::endl;}
};class TestB : public VirtualBase
{
private:int _num;public:TestB(int num, int data): _num(num), VirtualBase(data){}~TestB(){}void printData() override{std::cout << "TestB. Data: " << _num << std::endl;}
};int main()
{// 定義VirtualBase* virual_base_ptr = new VirtualBase(30);TestB* test_b_ptr = new TestB(40, 50);// 派生類指向父類,okVirtualBase* ptr_03 = dynamic_cast<VirtualBase*>(test_b_ptr);ptr_03->printData(); // ok// 父類指向指向派生類,errorTestB* ptr_04 = dynamic_cast<TestB*>(virual_base_ptr);// ptr_04->printData(); // error// 轉換失敗返回了nullptr,所以一般需要額外判斷if (ptr_04 != nullptr)ptr_04->printData();std::cout << "Finished! \n";return 0;
}
reinterpret_cast
轉換一個指針為其他類型的指針,也允許將一個指針轉換為整數類型,反之亦然。這個操作符能夠在非相關的類型之間進行轉換。操作結果只是簡單的從一個指針到別的指針的值的二進制拷貝,在類型之間指向的內容不做任何類型的檢查和轉換。這是一個強制轉換。使用時有很大的風險,慎用之。(反正少用就完事兒了)
const_cast
這個類型操縱傳遞對象的const屬性,或者是設置或者是移除(也不常用)
參考資料
C++ | 四種類型轉換_c++四種類型轉換-CSDN博客
https://www.cnblogs.com/daihanlong/p/5550530.html