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

C++超詳細(xì)講解RTTI和cast運(yùn)算符的使用

 更新時(shí)間:2022年08月19日 17:06:15   作者:Shawn-Summer  
RTTI(Runtime Type Identification)是“運(yùn)行時(shí)類型識(shí)別”的意思。C++引入這個(gè)機(jī)制是為了讓程序在運(yùn)行時(shí)能根據(jù)基類的指針或引用來(lái)獲得該指針或引用所指的對(duì)象的實(shí)際類型,cast強(qiáng)制轉(zhuǎn)換運(yùn)算符是一種特殊的運(yùn)算符,它把一種數(shù)據(jù)類型轉(zhuǎn)換為另一種數(shù)據(jù)類型

1. RTTI

RTTI是運(yùn)行階段類型識(shí)別(Running Type Identificarion)的簡(jiǎn)稱。

如何知道指針指向的是哪種對(duì)象?

這是個(gè)很常見(jiàn)的問(wèn)題,由于我們?cè)试S使用基類指針指向派生類,所以基類指針指向的對(duì)象可能是基類對(duì)象,也可能是派生類對(duì)象。但是我們需要知道對(duì)象種類,因?yàn)槲覀冃枰褂谜_的類方法。

RTTI能解決上述問(wèn)題。

1.1 dynamic_cast運(yùn)算符

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

什么是安全?

例如:A是基類,B是A的派生類,C是B的派生類。那么將BC對(duì)象的地址賦給A指針是安全的,而反向就是不安全的。因?yàn)楣欣^承滿足is-a關(guān)系,指針和引用進(jìn)行向上轉(zhuǎn)換是安全的,向下轉(zhuǎn)換就是不安全的。

dynamic_cast的用法是:

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

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

總之,dynamic_cast類型轉(zhuǎn)換運(yùn)算符比C風(fēng)格的類型轉(zhuǎn)換要安全的多,而且它能夠判斷轉(zhuǎn)換是否安全。

//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

上面這個(gè)例子說(shuō)明了重要的一點(diǎn):盡可能使用虛函數(shù),而只在必要時(shí)使用RTTI。

如果將dynamic_cast用于引用,當(dāng)請(qǐng)求不安全的時(shí)候,會(huì)引發(fā)bad_cast異常,這種異常時(shí)從exception類派生而來(lái)的,它在頭文件typeinfo中定義。

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

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

1.2 typeid運(yùn)算符

type_info類是在頭文件typeinfo中定義的一個(gè)類。type_info類重載了==!=運(yùn)算符。

typeid是一個(gè)運(yùn)算符,它返回一個(gè)對(duì)type_info的引用,它可以接受2種參數(shù):類名和對(duì)象。typeid是真正回答了"指針指向的是哪類對(duì)象"。

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

用法:

typeid(Magnificent)==typeid(*pg)

如果pg是一個(gè)空指針,則會(huì)引發(fā)bad_typeid異常。

type_info類中包含一個(gè)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!

注意,你可能發(fā)現(xiàn)了typeid遠(yuǎn)比dynamic_cast優(yōu)秀的多,typeid會(huì)直接告訴你類型是什么,而dynamic_cast只告訴你是否可以類型轉(zhuǎn)換。但是typeid的效率比dynamic_cast低很多,所以,請(qǐng)優(yōu)先考慮dynamic_cast和虛函數(shù),如果不行才使用typeid。

2. cast運(yùn)算符

C語(yǔ)言中的類型轉(zhuǎn)換符太過(guò)隨意,C++創(chuàng)始人認(rèn)為,我們應(yīng)該使用嚴(yán)格的類型轉(zhuǎn)換,則C++提供了4個(gè)類型轉(zhuǎn)換運(yùn)算符:

  • dynamic_cast
  • const_cast
  • static_cast
  • reinterpret_cast

dynamic_cast運(yùn)算符已經(jīng)介紹過(guò)了,它的用途是,使得類層次結(jié)構(gòu)中進(jìn)行向上轉(zhuǎn)換,而不允許其他轉(zhuǎn)換。

const_cast運(yùn)算符,用于除去或增加 類型的constvolatile屬性。

它的語(yǔ)法是:

const_cast<type-name>(expression)

如果類型的其他方面也被修改,則上述類型轉(zhuǎn)換就會(huì)出錯(cuò),也就是說(shuō),除了cv限定符可以不同外,type_nameexpression的類型必須相同。

提供該運(yùn)算符的目的是:有時(shí)候我們需要一個(gè)值:它在大多數(shù)情況下是常量,而有時(shí)候我們需要更改它。

看一個(gè)有趣的例子:

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

上面最后這個(gè)a常量被修改成255,這是我們預(yù)期的結(jié)果。但是如果我把volatile關(guān)鍵詞去掉,那么a的值還是100。其實(shí)是編譯器在這里玩了個(gè)小聰明,const int a=100,編譯器認(rèn)為a就不會(huì)發(fā)生改變了,所以就把a(bǔ)放在了寄存器中,因?yàn)樵L問(wèn)寄存器要比訪問(wèn)內(nèi)存單元快的多,每次都從寄存器中取數(shù)據(jù),但是后來(lái)a在內(nèi)存中發(fā)生變化后,寄存器中的數(shù)據(jù)沒(méi)有發(fā)生變化,所以打印的是寄存器中的數(shù)據(jù)。解決這一問(wèn)題,就使用volatile關(guān)鍵詞,那么對(duì)a的存取都是直接對(duì)內(nèi)存做操作的。

static_cast運(yùn)算符

它的語(yǔ)法是:

static_cast<type-name>(expression)

僅當(dāng)type-name可被隱式轉(zhuǎn)換成expression所屬的類型或者expression可以隱式轉(zhuǎn)換成type-name類型時(shí),上述轉(zhuǎn)換才合法,否則出現(xiàn)bad_cast異常。

例如,枚舉值可以隱式轉(zhuǎn)換成整型,那么整型就可以通過(guò)static_cast轉(zhuǎn)換成枚舉型。

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

reinterpret_cast運(yùn)算符:重新詮釋類型,進(jìn)行瘋狂的類型轉(zhuǎn)換

它的語(yǔ)法時(shí):

reinterpret_cast<type-name>(expression)

它可以進(jìn)行類型間"不可思議"的互換,但是它不允許刪除const,也不允許進(jìn)行喪失數(shù)據(jù)的轉(zhuǎn)換

例如下面這兩個(gè)例子:

#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轉(zhuǎn)換符適用于底層編程技術(shù),是不可移植的,因?yàn)椴煌到y(tǒng)可能使用不同大小,不同順序來(lái)存儲(chǔ)同一類型的數(shù)據(jù)。

總之,C語(yǔ)言類型轉(zhuǎn)換比reinterpret_cast還要"瘋狂",非常不安全,所以推薦使用cast運(yùn)算符來(lái)實(shí)現(xiàn)類型轉(zhuǎn)換。

到此這篇關(guān)于C++超詳細(xì)講解RTTI和cast運(yùn)算符的使用的文章就介紹到這了,更多相關(guān)C++ RTTI和cast內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 一文帶你了解Qt中槽的使用

    一文帶你了解Qt中槽的使用

    這篇文章主要為大家詳細(xì)介紹了Qt中槽的使用教程,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)Qt有一定的幫助,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2022-12-12
  • C++之BOOST字符串查找示例

    C++之BOOST字符串查找示例

    這篇文章主要介紹了C++之BOOST字符串查找的方法,實(shí)例演示了boost針對(duì)字符串的查找、判定及替換等操作,具有一定的實(shí)用價(jià)值,需要的朋友可以參考下
    2014-10-10
  • 利用C語(yǔ)言編寫“剪刀石頭布”小游戲

    利用C語(yǔ)言編寫“剪刀石頭布”小游戲

    這篇文章主要給大家介紹了關(guān)于如何利用C語(yǔ)言編寫“剪刀石頭布”小游戲的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12
  • OpenCV識(shí)別圖像上的線條軌跡

    OpenCV識(shí)別圖像上的線條軌跡

    這篇文章主要為大家詳細(xì)介紹了OpenCV識(shí)別圖像上的線條軌跡,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-07-07
  • C語(yǔ)言修煉之路悟徹?cái)?shù)組真妙理?巧用下標(biāo)破萬(wàn)敵下篇

    C語(yǔ)言修煉之路悟徹?cái)?shù)組真妙理?巧用下標(biāo)破萬(wàn)敵下篇

    在C語(yǔ)言和C++等語(yǔ)言中,數(shù)組元素全為指針變量的數(shù)組稱為指針數(shù)組,指針數(shù)組中的元素都必須具有相同的存儲(chǔ)類型、指向相同數(shù)據(jù)類型的指針變量。指針數(shù)組比較適合用來(lái)指向若干個(gè)字符串,使字符串處理更加方便、靈活
    2022-02-02
  • C++ LeeCode題目:比特位計(jì)數(shù)和買賣股票的最佳時(shí)機(jī)

    C++ LeeCode題目:比特位計(jì)數(shù)和買賣股票的最佳時(shí)機(jī)

    這篇文章主要介紹了基于C語(yǔ)言計(jì)算比特位計(jì)數(shù)和買賣股票的最佳時(shí)機(jī),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2021-07-07
  • Qt中QGroupBox控件的實(shí)現(xiàn)

    Qt中QGroupBox控件的實(shí)現(xiàn)

    QGroupBox 是 Qt 框架中一個(gè)非常有用的控件,它主要用于組織和管理一組相關(guān)的控件,本文主要介紹了Qt中QGroupBox控件的實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的可以了解一下
    2025-04-04
  • C++?DLL注入工具(完整源碼)

    C++?DLL注入工具(完整源碼)

    這篇文章主要介紹了C++?DLL注入工具的相關(guān)資料,并向大家分享了完整的源碼,具有一定的參考價(jià)值,希望對(duì)正在工作或?qū)W習(xí)的你有所幫助
    2022-02-02
  • C++中構(gòu)造函數(shù)與析構(gòu)函數(shù)的詳解及其作用介紹

    C++中構(gòu)造函數(shù)與析構(gòu)函數(shù)的詳解及其作用介紹

    這篇文章主要介紹了C++中構(gòu)造函數(shù)與析構(gòu)函數(shù)的詳解及其作用介紹,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-09-09
  • C++輸出問(wèn)題:保留兩位小數(shù)

    C++輸出問(wèn)題:保留兩位小數(shù)

    這篇文章主要介紹了C++輸出問(wèn)題:保留兩位小數(shù)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-11-11

最新評(píng)論

墨竹工卡县| 香港| 东光县| 那坡县| 茶陵县| 洪江市| 灵丘县| 惠州市| 根河市| 郎溪县| 沙坪坝区| 克东县| 正阳县| 綦江县| 报价| 利川市| 密云县| 英德市| 永济市| 禄劝| 宜丰县| 清新县| 长垣县| 涡阳县| 潜山县| 武安市| 阜宁县| 黄大仙区| 泰兴市| 瑞丽市| 大余县| 承德县| 白玉县| 锦州市| 通江县| 白城市| 苍溪县| 乳源| 独山县| 五台县| 咸丰县|