【C++】類型轉換(const_cast、dynamic_cast、static_cast、reinterpret_cast)

C語言風格的類型轉換符

C 語言風格的類型轉換符無需多說,下面兩種方式都可以,也是平時用的最多轉換符,沒有什麼特點,就是單純的將某個類型轉成另一個類型。後面講到每個 C++ 的轉換都會與 C 語言風格轉換進行對比。

int integer = 10;
double double1 = (int)integer;
double double2 = int(integer); 

const_cast

const_cast 一般用於去除 const 屬性,將 const 轉換成非 const 。
C 語言風格強轉也可以達到這個效果,並且與 const_cast 在使用效果上沒有任何區別(通過觀察底層彙編可知)。

#include <iostream>
using namespace std;

struct Person {
	int m_age;
};

int main() {
	
	const Person *p1 = new Person();
	// p1->m_age = 20; // p1是常量,無法修改
	
	Person *p2 = const_cast<Person *>(p1);	// const_cast 去 const
	p2->m_age = 20; // 去除了const,可以修改
	
	Person *p3 = (Person *)p1; 	// C語言風格強轉也可以,使用效果沒有任何區別
	p3->m_age = 20; // 去除了const,可以修改
	
	return 0;
}

如何通過觀察底層彙編得出結論?
首先,給程序打個斷點,進入調試,然後右鍵選擇反彙編(Alt + G)查看彙編:
在這裏插入圖片描述
觀察彙編可知,const_cast 相比 C語言風格強轉沒有多做任何事情,它的意義主要在於見名知意

dynamic_cast

  • 一般用於多態類型的轉換,有運行時安全檢測

dynamic_cast,有運行時安全檢測,檢測到不安全的轉化,則會將地址變爲NULL。而 C 語言風格轉化沒有安全檢測,即使不安全依舊可以強轉。

#include <iostream>
using namespace std;

class Person {
	virtual void run() {}
};

class Student : public Person {
};

int main() {
	Person *p1 = new Person();
	Person *p2 = new Student(); // 父類指針指向子類對象

	// dynamic_cast,有運行時安全檢測
	// 檢測到不安全的轉化,則會將地址變爲NULL
	Student *stu1 = dynamic_cast<Student *>(p1); // 不安全,地址變爲NULL
	Student *stu2 = dynamic_cast<Student *>(p2); // 安全

	// C語言風格轉化沒有安全檢測,即使不安全依舊可以強轉
	Student *stu3 = (Student *)p1; // 不安全,依舊可以轉
	Student *stu4 = (Student *)p2; // 安全

	cout << "stu1 = " << stu1 << endl; // 00000000
	cout << "stu2 = " << stu2 << endl; // 00DC0430
	cout << "stu3 = " << stu3 << endl; // 00DB6C20
	cout << "stu4 = " << stu4 << endl; // 00DC0430

	return 0;
}

static_cast

  • 對比 dynamic_cast ,缺乏運行時安全檢測
  • 不能交叉轉換(不是同一繼承體系的,無法轉換)
  • 常用於基本數據類型的轉換、非 const 轉成 const
  • 適用範圍較廣(但是用的很少)
#include <iostream>
using namespace std;

class Person {
	virtual void run() {}
};

class Student : public Person {
};

class Car {
};

int main() {
	Person *p1 = new Person();
	const Person *p2 = p1; // 不寫也會進行隱式轉換

	int a = 10; // 基本數據類型的轉換
	double d = static_cast<double>(a); // 效果與C語言風格轉換沒有任何區別

	// dynamic_cast 沒有交叉轉換的限制
	Car *c1 = dynamic_cast<Car *>(p1);
	// static_cast 不能交叉轉換
	// Car *c2 = static_cast<Car *>(p1); // 報錯,Person與Car毫無關聯,無法轉換
	
	return 0;
}

reinterpret_cast

  • 屬於比較底層的強制轉換,沒有任何類型檢查和格式轉換,僅僅是簡單的二進制數據拷貝
  • 可以交叉轉換
  • 可以將指針和整數互相轉換
#include <iostream>
using namespace std;

class Person {
	virtual void run() {}
};

class Student : public Person {
};

class Car {
};

int main() {
	Person *p1 = new Person(); 
	Person *p2 = new Student(); // 父類指針指向子類對象

	// 怎麼樣都能轉,但是由於轉換是二進制數據的拷貝
	// 轉換結果往往我們想的不一樣(差別極大)
	// 要達到我們所想的目的,往往採用C語言風格的強轉
	Student *stul = reinterpret_cast<Student *>(p1); 
	Student *stu2 = reinterpret_cast<Student *>(p2); 
	Car *car = reinterpret_cast<Car*>(p1); 

	int *p = reinterpret_cast<int *>(0x100); 
	int num = reinterpret_cast<int>(p); 
	
	int i = 10; 
	// 這裏就是要寫成 <double &>,語法規定,no why
	double d1 = reinterpret_cast<double &>(i);

	getchar();
	return 0;
}

總結

C++ 雖然提供了 4 種轉換方式,但是平時用的最多就是C語言風格的強轉
這 4 種方式主要是見名知意,而 C語言風格只知道是強轉,具體誰轉誰需要上下代碼。
不使用 C++ 風格的轉換方式對程序來說沒有任何影響。
C++ 提供的轉換方式要求不高,認識即可。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章