C++Primer第十九章的動态類型轉換部分講的不是很清楚,于是自己查cpp的官方手冊總結一下。
dynamic_cast < new-type > ( expression )
動态類型轉換是可以安全的在繼承體系将指針和引用進行向上、向下和橫向的轉換。其表達式的類型為運作時的動态類型。具體功能如下:
一、和隐式轉換,靜态轉換static_cast一樣的功能
1、增加const屬性:在expression和new-type類型相同或new-type為void*時,轉換結果為expression的指針或引用。并且可以在dynamic_cast前加上const限定符實作增加const屬性。
const dynamic_cast < new-type > ( expression )
2、向上轉換upcast:和static_cast和隐式轉換一樣,dynamic_cast可以将派生類轉換為基類。
二、dynamic_cast獨有的功能
如果expression是一個指向具有多态特性的基類Base的指針或引用(靜态類型),new-type是一個指向派生類Derived對象的指針或引用,具體進行那種轉換根據expression的動态類型判斷
1、向下轉換downcast:expression的動态類型為指向派生類Derived的指針或引用,并且Derived僅包含一份繼承自Base的對象,則轉換結果為指向Derived對象的指針或引用。(相當于從expressionh的父類轉換為子類)
2、橫向轉換sidecast:expression的動态類型為指向一個類的對象的指針或引用,該類公有繼承自Base和Derivied(Derived不一定繼承自Base)并且繼承自Derived的子成員是明确的(必須是虛繼承,不能有二義性)。則轉換結果為指向Derived的指針或引用。(相當于expression動态類型對象的一個父類轉換為另一個父類)
三、轉換失敗時如果轉換目标是指針類型則傳回空指針,引用類型抛出一個bad_cast異常。
這裡直接使用官方例子
1 #include <iostream>
2
3 struct V {
4 virtual void f() {} // must be polymorphic to use runtime-checked dynamic_cast
5 };
6 struct A : virtual V {};
7 struct B : virtual V {
8 B(V* v, A* a) {
9 // casts during construction (see the call in the constructor of D below)
10 dynamic_cast<B*>(v); // well-defined: v of type V*, V base of B, results in B*
11 dynamic_cast<B*>(a); // undefined behavior: a has type A*, A not a base of B
12 }
13 };
14 struct D : A, B {
15 D() : B(static_cast<A*>(this), this) { }
16 };
17
18 struct Base {
19 virtual ~Base() {}
20 };
21
22 struct Derived: Base {
23 virtual void name() {}
24 };
25
26 int main()
27 {
28 D d; // the most derived object
29 A& a = d; // upcast, dynamic_cast may be used, but unnecessary
30 [[maybe_unused]]
31 D& new_d = dynamic_cast<D&>(a); // downcast
32 [[maybe_unused]]
33 B& new_b = dynamic_cast<B&>(a); // sidecast
34
35
36 Base* b1 = new Base;
37 if(Derived* d = dynamic_cast<Derived*>(b1))
38 {
39 std::cout << "downcast from b1 to d successful\n";
40 d->name(); // safe to call
41 }
42
43 Base* b2 = new Derived;
44 if(Derived* d = dynamic_cast<Derived*>(b2))
45 {
46 std::cout << "downcast from b2 to d successful\n";
47 d->name(); // safe to call
48 }
49
50 delete b1;
51 delete b2;
52 }
downcast from b2 to d successful