dynamic_cast < type-id > ( expression )

本文引用於http://baike.baidu.com/link?url=Ao6yji5MV3UYwKzeEa1d33e5FrNNyOBagjz4EXcVQpKIdxllaTE51d-N0lAnx6dlY0myuVnyit9k5x_OUd_Jnq

用法

dynamic_cast < type-id > ( expression )

該運算符把expression轉換成type-id類型的對象。Type-id必須是類的指針、類的引用或者void*;
如果type-id是類指針類型,那麼expression也必須是一個指針,如果type-id是一個引用,那麼expression也必須是一個引用。
dynamic_cast運算符可以在執行期決定真正的類型。如果downcast是安全的(也就說,如果基類指針或者引用確實指向一個派生類對象)這個運算符會傳回適當轉型過的指針。如果downcast不安全,這個運算符會傳回空指針(也就是說,基類指針或者引用沒有指向一個派生類對象)。
dynamic_cast主要用於類層次間的上行轉換和下行轉換,還可以用於類之間的交叉轉換。
在類層次間進行上行轉換時,dynamic_caststatic_cast的效果是一樣的;
在進行下行轉換時,dynamic_cast具有類型檢查的功能,比static_cast更安全。
classB
{
public:
    intm_iNum;
    virtualvoid foo();
};
classD:public B
{
public:
    char*m_szName[100];
};
voidfunc(B *pb)
{
    D *pd1 =static_cast<D *>(pb);
    D *pd2 =dynamic_cast<D *>(pb);
}
在上面的代碼段中,如果pb指向一個D類型的對象,pd1和pd2是一樣的,並且對這兩個指針執行D類型的任何操作都是安全的;
但是,如果pb指向的是一個B類型的對象,那麼pd1將是一個指向該對象的指針,對它進行D類型的操作將是不安全的(如訪問m_szName),
而pd2將是一個空指針

2注意事項

B要有虛函數,否則會編譯出錯;static_cast則沒有這個限制。
B中需要檢測有虛函數的原因:類中存在虛函數,就說明它有想要讓基類指針或引用指向派生類對象的情況,此時轉換纔有意義。
這是由於運行時類型檢查需要運行時類型信息,而這個信息存儲在類的虛函數表(關於虛函數表的概念,詳細可見<Inside c++ object model>)中,只有定義了虛函數的類纔有虛函數表,
沒有定義虛函數的類是沒有虛函數表的。
另外,dynamic_cast還支持交叉轉換(cross cast)。如下代碼所示:
classA
{
public:
    intm_iNum;
    virtualvoid f(){}
};
classB:public A
{
};
classD:public A
{
};
voidfoo()
{
    B *pb =new B;
    pb->m_iNum = 100;
    D *pd1 =static_cast<D *>(pb);//compile error
    D *pd2 =dynamic_cast<D *>(pb);//pd2 is NULL
    deletepb;
}


在函數foo中,使用static_cast進行轉換是不被允許的,將在編譯時出錯,而使用dynamic_cast的轉換則是允許的,結果是空指針。

3運用實例

問題

1)什麼時候應必須使用dynamic_cast
2)什麼時候dynamic_cast可以使用static_cast代替

實例

// TestCast.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <iostream>
usingnamespace std;
classBase
{
public:
    virtualvoid f() { cout << "Base::f" << endl; }
    voidf1(){cout << "Base::f1"<< endl;}
private:
    doublex;
    doubley;
};
classDerived : publicBase
{
public:
    virtualvoid f(){cout << "Derived::f" << endl; }
    virtualvoid k(){cout << "Derived::k" << endl; }
private:
    doublez;
};
classBase1
{
public:
    virtualvoid g(){ cout << "Base1::g" << endl;}
    voidg1(){cout << "Base1::g1"<< endl;}
};
classDerived1 : publicBase,public Base1
{
public:
    virtualvoid f(){ cout << "Derived1::f" << endl;}
    virtualvoid h(){ cout << "Derived1::h" << endl;}
};
voidTest1()
{
    // 對於單繼承,
    // 如果pD真的指向Derived,用dynamic_cast和static_cast效果相同
    Base *pD =new Derived;
    Derived *pD1 =dynamic_cast<Derived*>(pD);
    pD1->f();
    pD1->k();
    pD1->f1();
    Derived *pD2 =static_cast<Derived*>(pD);
    pD2->f();
    pD2->k();
    pD2->f1();
    // 但是如果pB不是真的指向Derived,則用dynamic_cast則返回NULL,能夠更早的禁止error的發生,
    // 如果用static_cast雖然返回的不爲NULL,但是運行時可能拋出exception。
    /**///// Error code
    //Base *pB = new Base();
    //Derived *pD3 = static_cast<Derived*>(pB);
    //pD3->f();
    //pD3->k();
    //pD3->f1();
    //Derived *pD4 = dynamic_cast<Derived*>(pB);
    //pD4->f();
    //pD4->k();
    //pD4->f1();
}
voidTest2()
{
    // 對於多重繼承,
    // 如果pD真的指向的是Derived1,使用dynamic_cast和static_cast都可以轉化爲Derived1,
    // 但是如果要轉化爲Base的兄弟類Base1,必須使用dynamic_cast,使用static_cast不能編譯。
    Base *pD =new Derived1;
    Derived1 *pD1 =dynamic_cast<Derived1*>(pD);
    pD1->f();
    pD1->h();
    pD1->f1();
    Base1 *pB1 =dynamic_cast<Base1*>(pD);
    pB1->g();
    Derived1 *pD2 =static_cast<Derived1*>(pD);
    pD2->f();
    pD1->h();
    pD2->f1();
    /**///// error can not compiler
    //Base1 *pB2 = static_cast<Base1*>(pD);
    //pB2->g();
    // 當然對於pB不是真的指向Derived1,想要轉化爲Derived1或Base的兄弟類Base1,情況與Test1中的erro    r情況相同。
}
int _tmain(int argc, _TCHAR* argv[])
{
    Test1();
    Test2();
    return0;
}




發佈了53 篇原創文章 · 獲贊 4 · 訪問量 12萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章