C++隱式轉換與顯式轉換詳解
1.傳統(tǒng)的類型轉換
在 C 語言中,如果賦值運算符左右兩側類型不同,或者形參與實參類型不匹配,或者返回值類型與接收返回值類型不一致時,就需要發(fā)生類型轉化
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);
}轉換分為顯式和隱式:
- 隱式類型轉化:編譯器在編譯階段自動進行,能轉就轉,不能轉就編譯失敗
- 顯式類型轉化:需要用戶自己處理
然而這兩種轉換的前提是邏輯相近:
- 基本類型間的轉換(如 int ↔ double)
- 繼承層級中的轉換(如子類→父類、父類→子類)
- 用戶定義的轉換(如 operator T() 或帶參數(shù)的構造函數(shù))
string s; vector<int> = (vector<int>) s;
這種轉換就會失敗,因為邏輯不相近
對于強制轉換還有一種特殊易錯的場景
int main()
{
const int n = 10;
int* p = (int*) &n;
(*p)++;
string s;
vector<int> = (vector<int>) s;
cout << n << endl;
cout << *p << endl;
return 0;
}無論是有點 C 語言基礎的人,甚至是學完 C++ 的初學者,都很容易認為這里的輸出結果是:n 為 11,*p 為 11。但是結果并非所愿,輸出結果:n 為 10,*p 為 11
實際上這里涉及到存儲規(guī)則的問題,因為 n 是 const 變量,那么會被識別為一個常變量,可能會是一個經常被使用的值,就把 n 存入寄存器,把頻繁使用的變量的值暫存到寄存器中,這樣在后續(xù)對該變量的讀取操作中,就不需要每次都去內存中讀取,直接從寄存器中獲取即可,因為寄存器的讀寫速度比內存快很多
通常 cout 輸出的值都是在內存里讀取的,相比寄存器,內存讀寫速度較慢,但內存容量相對寄存器大很多,大多的代碼都是存在這里的
因此這里輸出的 n 是取自內存器,*p 取自內存
volatile const int n = 10;
volatile 關鍵字表示該變量的值可能會在程序未明確指定的情況下被改變,編譯器不會對其進行優(yōu)化,即不會被存入寄存器,這樣取到的 n 就是內存中及時更新的值
C 風格的轉換格式很簡單,但是有不少缺點的:
- 隱式類型轉化有些情況下可能會出問題:比如數(shù)據精度丟失
- 顯式類型轉換將所有情況混合在一起,代碼不夠清晰
因此 C++ 提出了自己的類型轉化風格,注意因為 C++ 要兼容 C 語言,所以 C++ 中還可以使用 C 語言的轉化風格
2.C++強制類型轉換
2.1 static_cast
int main()
{
double d = 12.34;
int a = static_cast<int>(d);
cout << a << endl;
return 0;
}
static_cast 需要邏輯上的相近性
2.2 reinterpret_cast
int main()
{
// 這里使用static_cast會報錯,應該使用reinterpret_cast
//int *p = static_cast<int*>(a);
int* p = reinterpret_cast<int*>(a);
return 0;
}
reinterpret_cast 幾乎無類型限制,不要求類型相近,可強制轉換任意指針或整數(shù)類型,但極其危險,可能導致:
- 違反別名規(guī)則(如通過 char* 修改 int)
- 函數(shù)指針轉換后調用,引發(fā)崩潰
- 平臺依賴(如不同架構的指針大小不同)
2.3 const_cast
void Test()
{
volatile const int a = 2;
int* p = const_cast<int*>(&a);
*p = 3;
cout << a << endl;
}
僅改變類型的 const / volatile 屬性,這里用 reinterpret_cast 也不行的,因為 const 的轉換是有風險的
2.4 dynamic_cast
class A
{
public:
virtual void f()
{}
};
class B : public A
{};
void fun(A* pa)
{
// dynamic_cast會先檢查是否能轉換成功,能成功則轉換,不能則返回
B* pb1 = static_cast<B*>(pa);
B* pb2 = dynamic_cast<B*>(pa);
cout << "pb1:" << pb1 << endl;
cout << "pb2:" << pb2 << endl;
}
int main()
{
A a;
B b;
fun(&a);
fun(&b);
return 0;
}dynamic_cast 用于將一個父類對象的指針/引用轉換為子類對象的指針或引用(動態(tài)轉換)
- 向上轉型: 子類對象指針/引用->父類指針/引用(不需要轉換,賦值兼容規(guī)則)
- 向下轉型: 父類對象指針/引用->子類指針/引用(用 dynamic_cast 轉型是安全的)
pa 是指向子類對象 B 的,轉換可以成功,正常返回地址;pa 是指向父類對象 A 的,轉換失敗,返回空指針
值得注意的是: 必須是繼承關系中的類,基類必須包含虛函數(shù)
3.RTTI
RTTI: Run-time Type identification 的簡稱,即:運行時類型識別
C++ 通過以下方式來支持 RTTI:
- typeid 運算符
- dynamic_cast 運算符
- decltype
以上就是C++隱式轉換與顯式轉換詳解的詳細內容,更多關于C++隱式轉換與顯式轉換的資料請關注腳本之家其它相關文章!
相關文章
delete[] p->elems和free(p->elems)區(qū)別介紹
delete[]和free()都是釋放內存的函數(shù),但它們具有不同的使用方法和適用情況,這篇文章主要介紹了delete[] p->elems和free(p->elems)有什么區(qū)別,需要的朋友可以參考下2023-04-04

