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++ 提供的轉換方式要求不高,認識即可。