91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

C++的RTTI和cast運算符如何使用

發布時間:2022-08-25 11:23:19 來源:億速云 閱讀:128 作者:iii 欄目:開發技術

本文小編為大家詳細介紹“C++的RTTI和cast運算符如何使用”,內容詳細,步驟清晰,細節處理妥當,希望這篇“C++的RTTI和cast運算符如何使用”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來學習新知識吧。

    1. RTTI

    RTTI是運行階段類型識別(Running Type Identificarion)的簡稱。

    如何知道指針指向的是哪種對象?

    這是個很常見的問題,由于我們允許使用基類指針指向派生類,所以基類指針指向的對象可能是基類對象,也可能是派生類對象。但是我們需要知道對象種類,因為我們需要使用正確的類方法。

    RTTI能解決上述問題。

    1.1 dynamic_cast運算符

    dynamic_cast是最常用的RTTI組件,它不能回答"指針指向的是哪類對象",但是它能回答"是否可以安全的將對象的地址賦給特定類型指針"。

    什么是安全?

    例如:A是基類,B是A的派生類,C是B的派生類。那么將BC對象的地址賦給A指針是安全的,而反向就是不安全的。因為公有繼承滿足is-a關系,指針和引用進行向上轉換是安全的,向下轉換就是不安全的。

    dynamic_cast的用法是:

    dynamic_cast<Type*>(ptr)dynamic_cast<Type&>(ref)

    可以看到的是,dynamic_cast是一種類型轉換符,它支持指針間的轉換,他將ptr的類型轉換成Type*,如果這種轉換是安全的,那會返回轉換后的指針;如果不安全那就會返回空指針。對于引用的話,他將ref的類型轉換成Type&,如果這種轉換是安全的,那就返回轉換后的引用;如果不安全那就會引發bad_cast異常。

    總之,dynamic_cast類型轉換運算符比C風格的類型轉換要安全的多,而且它能夠判斷轉換是否安全。

    //RTTI1.cpp
    #include<iostream>
    #include<cstdlib>
    #include<ctime>
    using namespace std;
    class Grand
    {
    protected:
        int hold;
    public:
        Grand(int h=0):hold(h){};
        virtual void Speak() const {cout<<"I am Grand class!\n";}
    };
    class Superb:public Grand
    {
    public:
        Superb(int h=0):Grand(h){}
        virtual void Speak() const {cout<<"I am a superb class!\n";}
        virtual void Say() const {cout<<"the value: "<<Grand::hold<<endl;}
    };
    class Magnificent:public Superb
    {
    private:
        char ch;
    public:
        Magnificent(int h=0,char c='A'):Superb(h),ch(c){}
        virtual void Speak() const{cout<<"I am a Magnificent class!\n";}
        virtual void Say() const{cout<<"the character: "<<ch<<endl<<"the value: "<<Grand::hold<<endl;}
    };
    Grand *GetOne();
    int main()
    {
        srand(time(0));
        Grand *pg;
        Superb *ps;
        for(int i=0;i<5;i++)
        {
            pg=GetOne();
            pg->Speak();
            if(ps=dynamic_cast<Superb*>(pg))
            {
                ps->Say();
            }
        }
        delete pg;
        return 0;
    }
    Grand * GetOne()
    {
        Grand *p;
        switch (rand()%3)
        {
            case 0:
                p=new Grand(rand()%100);
                break;
            case 1:
                p=new Superb(rand()%100);
                break;
            case 2:
                p=new Magnificent(rand()%100,'A'+rand()%26);
                break;
        }
        return p;
    }

    I am a Magnificent class!
    the character: I
    the value: 74
    I am a superb class!
    the value: 50
    I am Grand class!
    I am Grand class!
    I am a Magnificent class!
    the character: V
    the value: 99

    上面這個例子說明了重要的一點:盡可能使用虛函數,而只在必要時使用RTTI。

    如果將dynamic_cast用于引用,當請求不安全的時候,會引發bad_cast異常,這種異常時從exception類派生而來的,它在頭文件typeinfo中定義。

    則我們可以使用如下方式處理異常:

    #include<typeinfo>
    ...
    try{
        Superb & rs= dynamic_cast<Superb &>(rg);
        ....
    }
    catch(bad_cast &)
    {
        ...
    };

    1.2 typeid運算符

    type_info類是在頭文件typeinfo中定義的一個類。type_info類重載了==!=運算符。

    typeid是一個運算符,它返回一個對type_info的引用,它可以接受2種參數:類名和對象。typeid是真正回答了"指針指向的是哪類對象"。

    (實際上,typeid也可以用于其他類型,例如結構體,函數指針,各種類型,只要sizeof能接受的,typeid都能接受)

    用法:

    typeid(Magnificent)==typeid(*pg)

    如果pg是一個空指針,則會引發bad_typeid異常。

    type_info類中包含一個name()接口,該接口返回字符串,一般情況下是類的名稱。

    cout<<typeid(*pg).name()<<".\n"

    例子:

    //RTTI2.cpp
    #include<iostream>
    #include<cstdlib>
    #include<ctime>
    #include<typeinfo>
    using namespace std;
    class Grand
    {
    protected:
        int hold;
    public:
        Grand(int h=0):hold(h){};
        virtual void Speak() const {cout<<"I am Grand class!\n";}
    };
    class Superb:public Grand
    {
    public:
        Superb(int h=0):Grand(h){}
        virtual void Speak() const {cout<<"I am a superb class!\n";}
        virtual void Say() const {cout<<"the value: "<<Grand::hold<<endl;}
    };
    class Magnificent:public Superb
    {
    private:
        char ch;
    public:
        Magnificent(int h=0,char c='A'):Superb(h),ch(c){}
        virtual void Speak() const{cout<<"I am a Magnificent class!\n";}
        virtual void Say() const{cout<<"the character: "<<ch<<endl<<"the value: "<<Grand::hold<<endl;}
    };
    Grand *GetOne();
    int main()
    {
        srand(time(0));
        Grand *pg;
        Superb *ps;
        for(int i=0;i<5;i++)
        {
            pg=GetOne();
            cout<<"Now processing type "<<typeid(*pg).name()<<".\n";
            pg->Speak();
            if(ps=dynamic_cast<Superb*>(pg))
            {
                ps->Say();
            }
            if(typeid(Magnificent)==typeid(*pg))
            {
                cout<<"Yes,you are really magnificent.\n";
            }
        }
        delete pg;
        return 0;
    }
    Grand * GetOne()
    {
        Grand *p;
        switch (rand()%3)
        {
            case 0:
                p=new Grand(rand()%100);
                break;
            case 1:
                p=new Superb(rand()%100);
                break;
            case 2:
                p=new Magnificent(rand()%100,'A'+rand()%26);
                break;
        }
        return p;
    }

    Now processing type 6Superb.      
    I am a superb class!
    the value: 64
    Now processing type 11Magnificent.
    I am a Magnificent class!
    the character: Y
    the value: 30
    Yes,you are really magnificent.   
    Now processing type 5Grand.       
    I am Grand class!
    Now processing type 11Magnificent.
    I am a Magnificent class!
    the character: C
    the value: 3
    Yes,you are really magnificent.   
    Now processing type 5Grand.       
    I am Grand class!

    注意,你可能發現了typeid遠比dynamic_cast優秀的多,typeid會直接告訴你類型是什么,而dynamic_cast只告訴你是否可以類型轉換。但是typeid的效率比dynamic_cast低很多,所以,請優先考慮dynamic_cast和虛函數,如果不行才使用typeid

    2. cast運算符

    C語言中的類型轉換符太過隨意,C++創始人認為,我們應該使用嚴格的類型轉換,則C++提供了4個類型轉換運算符:

    • dynamic_cast

    • const_cast

    • static_cast

    • reinterpret_cast

    dynamic_cast運算符已經介紹過了,它的用途是,使得類層次結構中進行向上轉換,而不允許其他轉換。

    const_cast運算符,用于除去或增加 類型的constvolatile屬性。

    它的語法是:

    const_cast<type-name>(expression)

    如果類型的其他方面也被修改,則上述類型轉換就會出錯,也就是說,除了cv限定符可以不同外,type_nameexpression的類型必須相同。

    提供該運算符的目的是:有時候我們需要一個值:它在大多數情況下是常量,而有時候我們需要更改它。

    看一個有趣的例子:

    //cast運算符1.cpp
    //cast運算符1.cpp
    #include <iostream>
    int main()
    {
        using std::cout;
        using std::endl;
        volatile const int a=100;
        volatile const int & ra=a;//無法通過ra修改a
        int &change_a=const_cast<int &>(ra);//可以通過change_a修改a;
        change_a=255;
        cout<<a<<endl;
    }

    上面最后這個a常量被修改成255,這是我們預期的結果。但是如果我把volatile關鍵詞去掉,那么a的值還是100。其實是編譯器在這里玩了個小聰明,const int a=100,編譯器認為a就不會發生改變了,所以就把a放在了寄存器中,因為訪問寄存器要比訪問內存單元快的多,每次都從寄存器中取數據,但是后來a在內存中發生變化后,寄存器中的數據沒有發生變化,所以打印的是寄存器中的數據。解決這一問題,就使用volatile關鍵詞,那么對a的存取都是直接對內存做操作的。

    static_cast運算符

    它的語法是:

    static_cast<type-name>(expression)

    僅當type-name可被隱式轉換成expression所屬的類型或者expression可以隱式轉換成type-name類型時,上述轉換才合法,否則出現bad_cast異常。

    例如,枚舉值可以隱式轉換成整型,那么整型就可以通過static_cast轉換成枚舉型。

    總之,static_cast只允許"相似"的類型間的轉換,而不允許"差異很大"的類間的轉換。

    reinterpret_cast運算符:重新詮釋類型,進行瘋狂的類型轉換

    它的語法時:

    reinterpret_cast<type-name>(expression)

    它可以進行類型間"不可思議"的互換,但是它不允許刪除const,也不允許進行喪失數據的轉換

    例如下面這兩個例子:

    #include<iostream>
    int main()
    {
        using namespace std;
        struct dat {short a; short b;};
        long value =0xA224B118;
        dat *pd=reinterpret_cast<dat*>(&value);
        cout<<hex<<pd->a;
    }
    #include<iostream>
    void fun()
    {
        std::cout<<"hello world!\n";
    }
    int main()
    {
        using namespace std;
        void (*foo)();
        foo=fun;
        int* p=reinterpret_cast<int*>(foo);
    }

    通常,reinterpret_cast轉換符適用于底層編程技術,是不可移植的,因為不同系統可能使用不同大小,不同順序來存儲同一類型的數據。

    總之,C語言類型轉換比reinterpret_cast還要"瘋狂",非常不安全,所以推薦使用cast運算符來實現類型轉換。

    讀到這里,這篇“C++的RTTI和cast運算符如何使用”文章已經介紹完畢,想要掌握這篇文章的知識點還需要大家自己動手實踐使用過才能領會,如果想了解更多相關內容的文章,歡迎關注億速云行業資訊頻道。

    向AI問一下細節

    免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    AI

    嘉峪关市| 安达市| 常宁市| 潼南县| 沅陵县| 台前县| 长春市| 正镶白旗| 博乐市| 嘉禾县| 西城区| 聂荣县| 桐城市| 开远市| 石家庄市| 双桥区| 顺平县| 社旗县| 易门县| 和田市| 元氏县| 齐齐哈尔市| 莱西市| 德兴市| 马山县| 张家界市| 天全县| 北流市| 赤壁市| 盖州市| 朝阳县| 嘉义县| 新源县| 随州市| 漠河县| 合阳县| 安仁县| 维西| 大田县| 柞水县| 长春市|