第一章:C語言中的類型轉換
在C語言中,如果賦值運算符左右兩側類型不同,或者形參與實參類型不匹配,或者返回值類型與接收返回值類型不一致時,就需要發生類型轉化,C語言中總共有兩種形式的類型轉換:隱式類型轉換和顯式類型轉換。
- 隱式類型轉化:編譯器在編譯階段自動進行,能轉就轉,不能轉就編譯失敗
- 顯式類型轉化:需要用戶自己處理
void Test() {int i = 1;// 隱式類型轉換double d = i;printf("%d, %.2f\n", i, d);int* p = &i;// 顯示的強制類型轉換int address = (int)p;printf("%x, %d\n", p, address);
}
缺陷:
轉換的可視性比較差,所有的轉換形式都是以一種相同形式書寫,難以跟蹤錯誤的轉換
第二章:為什么C++需要四種類型轉換
C風格的轉換格式很簡單,但是有不少缺點的:?
- 隱式類型轉化有些情況下可能會出問題:比如數據精度丟失
- 顯式類型轉換將所有情況混合在一起,代碼不夠清晰
因此C++提出了自己的類型轉化風格,注意因為C++要兼容C語言,所以C++中還可以使用C語言的轉化風格。
第三章:C++強制類型轉換
標準C++為了加強類型轉換的可視性,引入了四種命名的強制類型轉換操作符:
static_cast、reinterpret_cast、const_cast、dynamic_cast
3.1 static_cast
static_cast用于非多態類型的轉換(靜態轉換),編譯器隱式執行的任何類型轉換都可用static_cast,但它不能用于兩個不相關的類型進行轉換
//相近類型用static_cast->意義相似的類型
int main() {double d = 12.34;int a = static_cast<int>(d);cout << a << endl;return 0;
}
3.2 reinterpret_cast
reinterpret_cast操作符通常為操作數的位模式提供較低層次的重新解釋,用于將一種類型轉換為另一種不同的類型
// 有一定的關聯,但是意義不相似的的類型用reinterpret_cast
int main() {double d = 12.34;int a = static_cast<int>(d);cout << a << endl;// 這里使用static_cast會報錯,應該使用reinterpret_cast//int *p = static_cast<int*>(a);int* p = reinterpret_cast<int*>(a);return 0;
}
3.3 const_cast
const_cast最常用的用途就是刪除變量的const屬性,方便賦值
int main() {const int a = 2;int* p = const_cast<int*>(&a);*p = 3;//當變量被聲明為const時,編譯器會假定它的值永遠不會改變,因此可以進行優化。//在編譯時,編譯器可能會直接用常量值替換所有對a的引用。cout << a << endl;//2 被編譯器優化為直接輸出2cout << *p << endl;//3 實際上訪問了內存中的值//地址相同cout << &a << endl;cout << p << endl;return 0;
}int main() {//告訴編譯器不要優化對該變量的訪問,每次讀取 a 時都必須從內存中重新加載,//而不是使用寄存器中的緩存或直接替換成常量。volatile const int a = 2;int* p = const_cast<int*>(&a);*p = 3;cout << a << endl;//3cout << *p << endl;//3 cout << &a << endl;//012FF93Ccout << p << endl;//012FF93Creturn 0;
}int main() {//使用強制類型轉換與const_cast相同const int a = 2;int* p = (int*)&a;*p = 3;cout << a << endl;//2cout << *p << endl;//3 //地址相同cout << &a << endl;cout << p << endl;return 0;
}
3.4 dynamic_cast
dynamic_cast用于將一個父類對象的指針/引用轉換為子類對象的指針或引用(動態轉換)
向上轉型:子類對象指針/引用->父類指針/引用(不需要轉換,賦值兼容規則)
向下轉型:父類對象指針/引用->子類指針/引用(用dynamic_cast轉型是安全的)
注意:
- dynamic_cast只能用于父類含有虛函數的類
- dynamic_cast會先檢查是否能轉換成功,能成功則轉換,不能則返回0
//必須是多態
class A {
public:virtual void f() {}int _a = 0;
};
class B : public A {
public:int _b = 1;
};//void fun(A* pa) {
// //向下轉換:直接轉換不完全
// //fun(&a); 是取a對象的地址,但是被強制轉換為B* 指針后,
// //會錯誤的以為_a后面還有個_b的成員變量,當取去修改_b時,其實修改的已經不是a對象的空間了
// B* ptr = (B*)pa;
// ptr->_a++;
// ptr->_b++;
//}
void fun(A* pa) {B* ptr = dynamic_cast<B*>(pa);//dynamic_cast的轉換:指向父類轉換失敗,返回空if (ptr) {ptr->_a++;ptr->_b++;cout << ptr->_a << " " << ptr->_b << endl;}else cout << "轉換失敗" << endl;}int main() {//B objb;//A obja = objb;//A& ra = objb;//這里沒有轉換,因為轉換有臨時變量,const引用才可以//向下轉換規則:父類對象不能轉換成子類對象,但父類指針和引用可以轉換為子類的指針和引用A a;B b;fun(&a);//轉換失敗fun(&b);//1 2return 0;
}
注意
強制類型轉換關閉或掛起了正常的類型檢查,每次使用強制類型轉換前,程序員應該仔細考慮是否還有其他不同的方法達到同一目的,如果非強制類型轉換不可,則應限制強制轉換值的作用域,以減少發生錯誤的機會。強烈建議:避免使用強制類型轉換。
第四章:4. RTTI
RTTI:Run-time Type identification的簡稱,即:運行時類型識別。
C++通過以下方式來支持RTTI:
- typeid運算符
- dynamic_cast運算符
- decltype
第五章:常見面試題
1. C++中的4中類型轉化分別是:_________、_________、_________、_________
2. 說說4中類型轉化的應用場景。