隱式類型轉換:
C++的隱式轉換發生在以下四種情況:
- 在混合類型的算術表達式中。
- 在表達式賦值中。
- 表達式傳給函數時,實參轉換為形參的類型。
- 函數返回表達式時轉換成返回值類型。
顯式類型轉換:
- 被稱為“強制類型轉換”(cast)
- C風格:(type-id)
- C++風格:
static_cast
、dynamic_cast
、reinterpret_cast
、和const_cast
1. static_cast
- 用法:
static_cast < type-id > ( expression )
- 通常用于轉換數值類型,進行非多態的類型轉換。
- 在轉換時不進行類型檢查,在編譯時進行類型檢查,如果轉換不成功則編譯錯誤,因此不安全。
// static_cast_Operator.cpp
// compile with: /LD
class B {};
class D : public B {};
void f(B* pb, D* pd) {
D* pd2 = static_cast<D*>(pb); // Down
// Not safe, D can have fields
// and methods that are not in B.
B* pb2 = static_cast<B*>(pd); // Up
// Safe conversion, D always contains all of B.
}
- 與 dynamic_cast 不同,pb 的 static_cast 轉換不執行運行時檢查。 由 pb 指向的對象可能不是 D 類型的對象,在這種情況下使用 *pd2 會是災難性的。 例如,調用 D 類(而非 B 類)的成員函數可能會導致訪問沖突。
2. dynamic_cast
- 用法:
dynamic_cast < type-id > ( expression )
- 用于指針和引用。不同類型的指針和引用之間的轉換。
-
注意:
dynamic_cast
在幫助你瀏覽繼承層次上是有限制的。它不能被用于缺乏虛函數的類型上。也即如果想將基類指針轉換為派生類指針,如果基類不是虛類則無法實現。 - 被用于安全地沿著類的繼承關系向下進行類型轉換。這就是說,你能用dynamic_cast把指向基類的指針或引用轉換成指向其派生類或其兄弟類的指針或引用,而且你能知道轉換是否成功。
- 向上轉換和static_cast作用一樣。不要求虛基類。
- 支持同一個基類的不同派生類指針之間的轉換。而
static_cast
則會報錯。 - 失敗的轉換將返回空指針(當對指針進行類型轉換時)或者拋出異常(當對引用進行類型轉換時)。例子如下。
// static_cast_Operator_2.cpp
// compile with: /LD /GR
class B {
public:
virtual void Test(){}
};
class D : public B {};
void f(B* pb) {
D* pd1 = dynamic_cast<D*>(pb);
D* pd2 = static_cast<D*>(pb);
}
- 如果
pb
確實指向 D 類型的對象,則pd1
和pd2
將獲取相同的值。 如果pb == 0
,它們也將獲取相同的值。 - 如果
pb
指向 B 類型的對象,而非指向完整的 D 類,則dynamic_cast
足以判斷返回零。 但是,static_cast
依賴于程序員的斷言,即pb
指向 D 類型的對象,因而只是返回指向那個假定的 D 對象的指針。
3. reinpreter_cast
- 用法:
reinpreter_cast<type-id> (expression)
-
type-id
必須是一個指針、引用、算術類型、函數指針或者成員指針。 - 它可以把一個指針轉換成一個整數,也可以把一個整數轉換成一個指針(先把一個指針轉換成一個整數,在把該整數轉換成原類型的指針,還可以得到原先的指針值)。
- 比較底層的轉換,在非相關的類型之間轉換。操作結果只是簡單的從一個指針到別的指針的值的二進制拷貝。在類型之間指向的內容不做任何類型的檢查和轉換。
reinpreter_cast
是特意用于底層的強制轉型,導致實現依賴(就是說,不可移植)的結果。
4. const_cast
- 用法:
const_cast<type_id> (expression)
- 該運算符用來修改類型的
const
或volatile
屬性。除了const
或volatile
修飾之外,type_id
和expression
的類型是一樣的。 - 常量指針被轉化成非常量指針,并且仍然指向原來的對象;常量引用被轉換成非常量引用,并且仍然指向原來的對象;常量對象被轉換成非常量對象。
關于多態的類指針轉換
- 向上轉換:派生類指針轉為基類指針。
- 向下轉換:基類指針轉換為派生類指針。
見下面這個例子:
class A {
public:
A() {
a = 0;
}
private:
int a;
};
class B : public A {
public:
B() {
b = 0;
}
private:
int b;
};
int main() {
A *pa1, *pa2, *pa3, *pa4;
B *pb1, *pb2, *pb3;
A a1;
pa1 = &a1;
B b1;
pb1 = &b1;
// 首先,對于指針直接指向對象:
pa2 = &b1; // Correct 指針pa直接指向B中A有的一部分
pb2 = &a1; // Error 需要進行強制類型轉換來縮小pb指針的范圍
// error: invalid conversion from 'A*' to 'B*'
// 指針之間的轉換
pa3 = dynamic_cast<A*>(pb3); // Up Correct 見上,使得指針能夠正常工作
pb3 = dynamic_cast<B*>(pa4); // Down Error
// error: cannot dynamic_cast 'pa4' (of type 'class A*') to type 'class B*' (source type is not polymorphic)
// 由于類A不是虛基類,不能將其指針pa轉換為類B的指針,因為類B的指針能夠對A中沒有的內容進行操作,直接轉換則不能做到。若A為虛基類,B是對A中方法的重寫,則能夠正確轉換
return 0;
}
例子:
- 此轉換類型稱為“向上轉換”,因為它將在類層次結構上的指針,從派生的類移到該類派生的類。 向上轉換是一種隱式轉換。
class B { };
class C : public B { };
class D : public C { };
void f(D* pd) {
C* pc = dynamic_cast<C*>(pd); // ok: C is a direct base class
// pc points to C subobject of pd
B* pb = dynamic_cast<B*>(pd); // ok: B is an indirect base class
// pb points to B subobject of pd
}
- 此轉換類型稱為“向下轉換”,因為它將在類層次結構下的指針,從給定的類移到該類派生的類。
class B {virtual void f();};
class D : public B {virtual void f();};
void f() {
B* pb = new D; // unclear but ok
B* pb2 = new B;
D* pd = dynamic_cast<D*>(pb); // ok: pb actually points to a D
D* pd2 = dynamic_cast<D*>(pb2); // pb2 points to a B not a D
}
參考閱讀
static_cast, dynamic_cast, const_cast探討
static_cast 運算符
dynamic_cast 運算符