C++中的四種動態類型轉換


在C語言中,強制類型的轉換方式很簡單,通過Type a = (Type)b即可,但是這樣有兩個比較明顯的缺點:一是轉換方式過於隨意,可以在指針和整數之間進行轉換,這是比較危險的操作;二是這樣的轉換方式在多括號的情況下不夠清晰和直接,進而C++推出了自己的轉換方式來改善這兩種情況。C++顯式類型轉換有四種const_cast、static_cast、dynamic_cast、reinterpreter_cast,四種轉換方式各有用途,需要針對不同情況選取不同的轉換方式。

static_cast

static_cast是一種最常用的轉型方式,我們可以在日常轉型操作中首先嘗試使用它,可能在很多場景中不需要它也能夠隱式的完成轉型操作,但是我們還是盡可能的將轉型操作顯式的表現出來。

可以完成以下類型的轉換

  • 基本類型的轉換(char轉int,int轉float之類)
  • void類型空指針轉其他類型空指針
  • 任意類型轉void類型指針
  • 父類到子類的轉換(不保證正確)
  • 子類到父類的轉換(保證正確)

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

const_cast

用於將const變量轉換為非const變量,這是其他任何轉換類型所沒有的功能。需要注意兩個點

  1. 去除const屬性不是對於最初的const對象來說,修改最初的const對象仍舊是未定義的,去除const屬性是指從引用或指針的方式來去除const屬性。
  2. const_cast只適用於指針或者引用方式
#include <iostream>
using namespace std;

class A
{
public:
	void print() { cout << "hello" << endl; }
	void print() const { cout << "world" << endl; }
};

int main(){
    const int a=100;
    cout << &a << "  :  " << a << endl;
    int &b = const_cast<int&>(a);
    b = 110;
    cout << &b << "  :  " <<  b << endl;
    int *pa = const_cast<int*>(&a);
    *pa = 120;
    cout << pa << "  :  " << *pa << endl;
    cout << &a << "  :  " << a << endl;
    cout << &b << "  :  " <<  b << endl;
    
    A a;
	a.print();
	const A b;
	b.print();
	A& ref = const_cast<A&>(b);
	A* ptr = const_cast<A*>(&b);
	ref.print();
	ptr->print();
}

輸出:
0x7ffcd8468304  :  100
0x7ffcd8468304  :  110
0x7ffcd8468304  :  120
0x7ffcd8468304  :  100
0x7ffffe03f164  :  120
hello
world
hello
hello

這里明明地址一樣,為什么a和b,*pa的值會不一樣呢?

答:a其實用const修飾后是一個常量,在預編譯階段,常量會被真實數值替換,所以並不是cout << a << endl;而是cout << 100 << endl;

dynamic_cast

dynamic_cast轉換主要用於多態方面的轉換,例如父類與子類之間的互相轉換。在轉換過程中如果能夠成功轉換就返回目標類型的指針,如果不行的話就返回空指針(用指針方式轉換)或者拋出異常(用引用方式轉換)。在進行upcast時,static_cast和dynamic_cast具有相同的效果;但在downcast(向下轉換,也就是父類向子類轉換)時,dynamic_cast相對於static_cast有一個類型檢查,相對來說更加安全。另外需要注意的是:

  1. 如果子類不是通過public繼承父類的話,那么轉換會失敗。這是因為父類的public成員因為private繼承變成了private屬性(對於子類而言),子類的指針無法訪問父類中的非private成員,就會出現轉換失敗的問題
class A {
private:
	int a;
public:
	A(int a_) :a(a_) {}
	virtual void vprintfself(void) {
		std::cout <<"a"<<this->a<<std::endl;
	}
};
class B: public A {
private:
	int b;
public:
	B(int a_,int b_) :A(a_) { b = b_; }
	void vprintfself(void) {
		std::cout <<"b "<<this->b<< std::endl;
	}
};
int main()
{

	A* a = new A(2);
	B* static_p_a_B = static_cast<B*>(a);
	B* dymatic_p_a_B =dynamic_cast<B*>(a);//空指針
	static_p_a_B->vprintfself();
	dymatic_p_a_B->vprintfself();//報錯

}

reinterpret_cast

interpret是解釋的意思,reinterpret即為重新解釋。這個轉換幾乎沒什么條件限制,可以將任何指針類型轉化為其他指針類型,少用為佳。

參考:

  1. https://zhuanlan.zhihu.com/p/83856596
  2. https://stackoverflow.com/questions/332030/when-should-static-cast-dynamic-cast-const-cast-and-reinterpret-cast-be-used
  3. https://www.jianshu.com/p/f2631fc62bde


免責聲明!

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



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