最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

淺析C++中dynamic_cast和static_cast實例語法詳解

 更新時間:2021年07月25日 08:53:20   作者:進(jìn)擊的汪sir  
這篇文章主要介紹了淺析C++中dynamic_cast和static_cast實例演示,包括static_cast語法知識和static_cast的作用講解,namic_cast 語法詳解,需要的朋友可以參考下

1. static_cast

1.1 static_cast語法

static_cast< new_type >(expression)

備注:new_type為目標(biāo)數(shù)據(jù)類型,expression為原始數(shù)據(jù)類型變量或者表達(dá)式。

C風(fēng)格寫法:

double scores = 96.5;
int n = (int)scores;

C++ 新風(fēng)格的寫法為:

double scores = 96.5;
int n = static_cast<int>(scores);

1.2 為什么要有static_cast等

隱式類型轉(zhuǎn)換是安全的,顯式類型轉(zhuǎn)換是有風(fēng)險的,C語言之所以增加強(qiáng)制類型轉(zhuǎn)換的語法,就是為了強(qiáng)調(diào)風(fēng)險,讓程序員意識到自己在做什么。

但是,這種強(qiáng)調(diào)風(fēng)險的方式還是比較粗放,粒度比較大,它并沒有表明存在什么風(fēng)險,風(fēng)險程度如何。

為了使?jié)撛陲L(fēng)險更加細(xì)化,使問題追溯更加方便,使書寫格式更加規(guī)范,C++ 對類型轉(zhuǎn)換進(jìn)行了分類,并新增了四個關(guān)鍵字來予以支持,它們分別是:

關(guān)鍵字 說明
static_cast 用于良性轉(zhuǎn)換,一般不會導(dǎo)致意外發(fā)生,風(fēng)險很低。
const_cast 用于 const 與非 const、volatile 與非 volatile 之間的轉(zhuǎn)換。
reinterpret_cast 高度危險的轉(zhuǎn)換,這種轉(zhuǎn)換僅僅是對二進(jìn)制位的重新解釋,不會借助已有的轉(zhuǎn)換規(guī)則對數(shù)據(jù)進(jìn)行調(diào)整,但是可以實現(xiàn)最靈活的 C++ 類型轉(zhuǎn)換。
dynamic_cast 借助 RTTI,用于類型安全的向下轉(zhuǎn)型(Downcasting)。

1.2 static_cast的作用

static_cast相當(dāng)于傳統(tǒng)的C語言里的強(qiáng)制轉(zhuǎn)換,該運算符把expression轉(zhuǎn)換為new_type類型,用來強(qiáng)迫隱式轉(zhuǎn)換如non-const對象轉(zhuǎn)為const對象,編譯時檢查,用于非多態(tài)的轉(zhuǎn)換,可以轉(zhuǎn)換指針及其他,但沒有運行時類型檢查來保證轉(zhuǎn)換的安全性。它主要有如下幾種用法:

風(fēng)險較低的用法:

  • 原有的自動類型轉(zhuǎn)換,例如 short 轉(zhuǎn) int、int 轉(zhuǎn) double、const 轉(zhuǎn)非 const、向上轉(zhuǎn)型等;
  • void 指針和具體類型指針之間的轉(zhuǎn)換,例如void *轉(zhuǎn)int *、char *轉(zhuǎn)void *等;
  • 有轉(zhuǎn)換構(gòu)造函數(shù)或者類型轉(zhuǎn)換函數(shù)的類與其它類型之間的轉(zhuǎn)換,例如 double 轉(zhuǎn) Complex(調(diào)用轉(zhuǎn)換構(gòu)造函數(shù))、Complex 轉(zhuǎn) double(調(diào)用類型轉(zhuǎn)換函數(shù))。

需要注意的是,static_cast 不能用于無關(guān)類型之間的轉(zhuǎn)換,因為這些轉(zhuǎn)換都是有風(fēng)險的,例如:

  • 兩個具體類型指針之間的轉(zhuǎn)換,例如int *轉(zhuǎn)double *、Student *轉(zhuǎn)int *等。不同類型的數(shù)據(jù)存儲格式不一樣,長度也不一樣,用 A 類型的指針指向 B 類型的數(shù)據(jù)后,會按照 A 類型的方式來處理數(shù)據(jù):如果是讀取操作,可能會得到一堆沒有意義的值;如果是寫入操作,可能會使 B 類型的數(shù)據(jù)遭到破壞,當(dāng)再次以 B 類型的方式讀取數(shù)據(jù)時會得到一堆沒有意義的值。
  • int 和指針之間的轉(zhuǎn)換。將一個具體的地址賦值給指針變量是非常危險的,因為該地址上的內(nèi)存可能沒有分配,也可能沒有讀寫權(quán)限,恰好是可用內(nèi)存反而是小概率事件。

1.3 static_cast用法

#include <iostream>
#include <cstdlib>
using namespace std;
class Complex{
public:
    Complex(double real = 0.0, double imag = 0.0): m_real(real), m_imag(imag){ }
public:
    operator double() const { return m_real; }  //類型轉(zhuǎn)換函數(shù)
private:
    double m_real;
    double m_imag;
};
int main(){
    //下面是正確的用法
    int m = 100;
    Complex c(12.5, 23.8);
    long n = static_cast<long>(m);  //寬轉(zhuǎn)換,沒有信息丟失
    char ch = static_cast<char>(m);  //窄轉(zhuǎn)換,可能會丟失信息
    int *p1 = static_cast<int*>( malloc(10 * sizeof(int)) );  //將void指針轉(zhuǎn)換為具體類型指針
    void *p2 = static_cast<void*>(p1);  //將具體類型指針,轉(zhuǎn)換為void指針
    double real= static_cast<double>(c);  //調(diào)用類型轉(zhuǎn)換函數(shù)
   
    //下面的用法是錯誤的
    float *p3 = static_cast<float*>(p1);  //不能在兩個具體類型的指針之間進(jìn)行轉(zhuǎn)換
    p3 = static_cast<float*>(0X2DF9);  //不能將整數(shù)轉(zhuǎn)換為指針類型
    return 0;
}

2. dynamic_cast

2.1 dynamic_cast 語法

dynamic_cast <newType> (expression)

newType 和 expression 必須同時是指針類型或者引用類型。換句話說,dynamic_cast 只能轉(zhuǎn)換指針類型和引用類型,其它類型(int、double、數(shù)組、類、結(jié)構(gòu)體等)都不行。

對于指針,如果轉(zhuǎn)換失敗將返回 NULL;對于引用,如果轉(zhuǎn)換失敗將拋出std::bad_cast異常。

2.2 dynamic_cast 用法

dynamic_cast 用于在類的繼承層次之間進(jìn)行類型轉(zhuǎn)換,它既允許向上轉(zhuǎn)型(Upcasting),也允許向下轉(zhuǎn)型(Downcasting)。向上轉(zhuǎn)型是無條件的,不會進(jìn)行任何檢測,所以都能成功;向下轉(zhuǎn)型的前提必須是安全的,要借助 RTTI 進(jìn)行檢測,所有只有一部分能成功。

dynamic_cast 與 static_cast 是相對的,dynamic_cast 是“動態(tài)轉(zhuǎn)換”的意思,static_cast 是“靜態(tài)轉(zhuǎn)換”的意思。dynamic_cast 會在程序運行期間借助 RTTI 進(jìn)行類型轉(zhuǎn)換,這就要求基類必須包含虛函數(shù);static_cast 在編譯期間完成類型轉(zhuǎn)換,能夠更加及時地發(fā)現(xiàn)錯誤。

2.3 dynamic_cast 實例

2.3.1 向上轉(zhuǎn)型(Upcasting)

向上轉(zhuǎn)型時,只要待轉(zhuǎn)換的兩個類型之間存在繼承關(guān)系,并且基類包含了虛函數(shù)(這些信息在編譯期間就能確定),就一定能轉(zhuǎn)換成功。因為向上轉(zhuǎn)型始終是安全的,所以 dynamic_cast 不會進(jìn)行任何運行期間的檢查,這個時候的 dynamic_cast 和 static_cast 就沒有什么區(qū)別了。

「向上轉(zhuǎn)型時不執(zhí)行運行期檢測」雖然提高了效率,但也留下了安全隱患,請看下面的代碼:

#include <iostream>
#include <iomanip>
using namespace std;
class Base{
public:
    Base(int a = 0): m_a(a){ }
    int get_a() const{ return m_a; }
    virtual void func() const { }
protected:
    int m_a;
};

class Derived: public Base{
public:
    Derived(int a = 0, int b = 0): Base(a), m_b(b){ }
    int get_b() const { return m_b; }
private:
    int m_b;
};

int main(){
    //情況①
    Derived *pd1 = new Derived(35, 78);
    Base *pb1 = dynamic_cast<Derived*>(pd1);
    cout<<"pd1 = "<<pd1<<", pb1 = "<<pb1<<endl;
    cout<<pb1->get_a()<<endl;
    pb1->func();
    //情況②
    int n = 100;
    Derived *pd2 = reinterpret_cast<Derived*>(&n);
    Base *pb2 = dynamic_cast<Base*>(pd2);
    cout<<"pd2 = "<<pd2<<", pb2 = "<<pb2<<endl;
    cout<<pb2->get_a()<<endl;  //輸出一個垃圾值
    pb2->func();  //內(nèi)存錯誤
    return 0;
}

運行結(jié)果如下

可以看到pd1與pb1的地址相同,且pb1可以正常調(diào)用Base類的方法

對于情況②

pd 2指向的是整型變量 n,并沒有指向一個 Derived 類的對象,在使用 dynamic_cast 進(jìn)行類型轉(zhuǎn)換時也沒有檢查這一點(因為向上轉(zhuǎn)型始終是安全的,所以 dynamic_cast 不會進(jìn)行任何運行期間的檢查)

而是將 pd 的值直接賦給了 pb(這里并不需要調(diào)整偏移量),最終導(dǎo)致 pb 也指向了 n。因為 pb 指向的不是一個對象,所以get_a()得不到 m_a 的值(實際上得到的是一個垃圾值),pb2->func()也得不到 func() 函數(shù)的正確地址。

運行結(jié)果如下

簡單來說就是向上轉(zhuǎn)型是不檢查的,所以大家得知道自己在做什么,不能隨意的轉(zhuǎn)換

2.3.2 向下轉(zhuǎn)型(Downcasting)

向下轉(zhuǎn)型是有風(fēng)險的,dynamic_cast 會借助 RTTI 信息進(jìn)行檢測,確定安全的才能轉(zhuǎn)換成功,否則就轉(zhuǎn)換失敗。

下面看一個例子

#include <iostream>
using namespace std;
class A{
public:
    virtual void func() const { cout<<"Class A"<<endl; }
private:
    int m_a;
};
class B: public A{
public:
    virtual void func() const { cout<<"Class B"<<endl; }
private:
    int m_b;
};
class C: public B{
public:
    virtual void func() const { cout<<"Class C"<<endl; }
private:
    int m_c;
};
class D: public C{
public:
    virtual void func() const { cout<<"Class D"<<endl; }
private:
    int m_d;
};
int main(){
    A *pa = new A();
    B *pb;
    C *pc;
   
    //情況①
    pb = dynamic_cast<B*>(pa);  //向下轉(zhuǎn)型失敗
    if(pb == NULL){
        cout<<"Downcasting failed: A* to B*"<<endl;
    }else{
        cout<<"Downcasting successfully: A* to B*"<<endl;
        pb -> func();
    }
    pc = dynamic_cast<C*>(pa);  //向下轉(zhuǎn)型失敗
    if(pc == NULL){
        cout<<"Downcasting failed: A* to C*"<<endl;
    }else{
        cout<<"Downcasting successfully: A* to C*"<<endl;
        pc -> func();
    }
   
    cout<<"-------------------------"<<endl;
   
    //情況②
    pa = new D();  //向上轉(zhuǎn)型都是允許的
    pb = dynamic_cast<B*>(pa);  //向下轉(zhuǎn)型成功
    if(pb == NULL){
        cout<<"Downcasting failed: A* to B*"<<endl;
    }else{
        cout<<"Downcasting successfully: A* to B*"<<endl;
        pb -> func();
    }
    pc = dynamic_cast<C*>(pa);  //向下轉(zhuǎn)型成功
    if(pc == NULL){
        cout<<"Downcasting failed: A* to C*"<<endl;
    }else{
        cout<<"Downcasting successfully: A* to C*"<<endl;
        pc -> func();
    }
   
    return 0;
}

運行結(jié)果

可以看到,前兩次轉(zhuǎn)換失敗,但是后兩次轉(zhuǎn)換成功

這段代碼中類的繼承順序為:A --> B --> C --> D。pa 是A*類型的指針,當(dāng) pa 指向 A 類型的對象時,向下轉(zhuǎn)型失敗,pa 不能轉(zhuǎn)換為B*C*類型。當(dāng) pa 指向 D 類型的對象時,向下轉(zhuǎn)型成功,pa 可以轉(zhuǎn)換為B*C*類型。同樣都是向下轉(zhuǎn)型,為什么 pa 指向的對象不同,轉(zhuǎn)換的結(jié)果就大相徑庭呢?

因為每個類都會在內(nèi)存中保存一份類型信息,編譯器會將存在繼承關(guān)系的類的類型信息使用指針“連接”起來,從而形成一個繼承鏈(Inheritance Chain),也就是如下圖所示的樣子:

當(dāng)使用 dynamic_cast 對指針進(jìn)行類型轉(zhuǎn)換時,程序會先找到該指針指向的對象,再根據(jù)對象找到當(dāng)前類(指針指向的對象所屬的類)的類型信息,并從此節(jié)點開始沿著繼承鏈向上遍歷,如果找到了要轉(zhuǎn)化的目標(biāo)類型,那么說明這種轉(zhuǎn)換是安全的,就能夠轉(zhuǎn)換成功,如果沒有找到要轉(zhuǎn)換的目標(biāo)類型,那么說明這種轉(zhuǎn)換存在較大的風(fēng)險,就不能轉(zhuǎn)換。

所以在第二種方式中,pa實際上是指向的D,于是程序順著D開始向上找,找到了B和C,于是認(rèn)定是安全的,所以轉(zhuǎn)換成功

總起來說,dynamic_cast 會在程序運行過程中遍歷繼承鏈,如果途中遇到了要轉(zhuǎn)換的目標(biāo)類型,那么就能夠轉(zhuǎn)換成功,如果直到繼承鏈的頂點(最頂層的基類)還沒有遇到要轉(zhuǎn)換的目標(biāo)類型,那么就轉(zhuǎn)換失敗。對于同一個指針(例如 pa),它指向的對象不同,會導(dǎo)致遍歷繼承鏈的起點不一樣,途中能夠匹配到的類型也不一樣,所以相同的類型轉(zhuǎn)換產(chǎn)生了不同的結(jié)果。

3. 參考鏈接

http://c.biancheng.net/cpp/biancheng/view/3297.html

https://blog.csdn.net/u014624623/article/details/79837849
https://www.cnblogs.com/wanghongyang/ 【本文博客】

到此這篇關(guān)于淺析C++中dynamic_cast和static_cast實例演示的文章就介紹到這了,更多相關(guān)C++中dynamic_cast與static_cast內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • OpenCV 圖像金字塔的實現(xiàn)示例

    OpenCV 圖像金字塔的實現(xiàn)示例

    本文將結(jié)合實例代碼,介紹OpenCV 圖像金字塔,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-06-06
  • C語言實現(xiàn)高精度加法的示例代碼

    C語言實現(xiàn)高精度加法的示例代碼

    高精度的本質(zhì)是將數(shù)字以字符串的形式讀入,然后將每一位分別存放入int數(shù)組中,通過模擬每一位的運算過程,來實現(xiàn)最終的運算效果,下面我們就來看看如何通過C語言實現(xiàn)高精度加法吧
    2023-11-11
  • C++ CryptoPP使用AES實現(xiàn)加解密詳解

    C++ CryptoPP使用AES實現(xiàn)加解密詳解

    Crypto++ (CryptoPP) 是一個用于密碼學(xué)和加密的 C++ 庫,提供了大量的密碼學(xué)算法和功能,這篇文章主要為大家介紹了C++ CryptoPP如何使用AES實現(xiàn)加解密,需要的可以參考下
    2023-11-11
  • OpenCV透視變換應(yīng)用之書本視圖矯正+廣告屏幕切換

    OpenCV透視變換應(yīng)用之書本視圖矯正+廣告屏幕切換

    透視變換是指利用透視中心、像點、目標(biāo)點三點共線的條件,按透視旋轉(zhuǎn)定律使承影面繞跡線旋轉(zhuǎn)某一角度,破壞原有的投影光線束,仍能保持承影面上投影幾何圖形不變的變換。本文將為大家介紹兩個OpenCV透視變換應(yīng)用,需要的可以參考一下
    2022-08-08
  • VS2017+Qt5+Opencv3.4調(diào)用攝像頭拍照并存儲

    VS2017+Qt5+Opencv3.4調(diào)用攝像頭拍照并存儲

    本文主要介紹了VS2017+Qt5+Opencv3.4調(diào)用攝像頭拍照并存儲,實現(xiàn)了視頻,拍照,保存這三個功能。具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-05-05
  • 淺談使用C++多級指針存儲海量qq號和密碼

    淺談使用C++多級指針存儲海量qq號和密碼

    這篇文章主要介紹了淺談使用C++多級指針存儲海量qq號和密碼,分享了相關(guān)實例代碼,具有一定借鑒價值,需要的朋友可以參考下
    2018-01-01
  • QT打包發(fā)布全流程(圖文教程)

    QT打包發(fā)布全流程(圖文教程)

    本文主要介紹了QT打包發(fā)布全流程,文中通過圖文介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-07-07
  • Qt實現(xiàn)計算器功能

    Qt實現(xiàn)計算器功能

    這篇文章主要為大家詳細(xì)介紹了Qt實現(xiàn)計算器功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-08-08
  • C語言切割多層字符串(strtok_r strtok使用方法)

    C語言切割多層字符串(strtok_r strtok使用方法)

    這篇文章主要介紹了C語言切割多層字符串的方法,說了strtok的弱點,使用strtok_r的方法
    2013-11-11
  • C++ 中this指針的用途詳解

    C++ 中this指針的用途詳解

    這篇文章主要給大家介紹了關(guān)于C++ 中this指針的用途,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用C++具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-09-09

最新評論

华容县| 上思县| 寻甸| 麻城市| 琼海市| 梓潼县| 梓潼县| 秦安县| 宜春市| 收藏| 阿克陶县| 汶川县| 健康| 买车| 龙江县| 清新县| 双牌县| 忻城县| 哈尔滨市| 万安县| 河曲县| 右玉县| 清徐县| 朔州市| 台江县| 莱州市| 万源市| 台前县| 武邑县| 灵璧县| 万全县| 林口县| 大荔县| 密山市| 晋江市| 深圳市| 东方市| 东源县| 获嘉县| 乐亭县| 石景山区|