国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達(dá)式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務(wù)器之家 - 編程語言 - C/C++ - C++中的RTTI機(jī)制詳解

C++中的RTTI機(jī)制詳解

2021-02-05 14:13果凍想 C/C++

這篇文章主要介紹了C++中的RTTI機(jī)制詳解,本文詳細(xì)的總結(jié)了RTTI的相關(guān)知識(shí),需要的朋友可以參考下

前言

RTTI是”Runtime Type Information”的縮寫,意思是運(yùn)行時(shí)類型信息,它提供了運(yùn)行時(shí)確定對(duì)象類型的方法。RTTI并不是什么新的東西,很早就有了這個(gè)技術(shù),但是,在實(shí)際應(yīng)用中使用的比較少而已。而我這里就是對(duì)RTTI進(jìn)行總結(jié),今天我沒有用到,并不代表這個(gè)東西沒用。學(xué)無止境,先從typeid函數(shù)開始講起。

typeid函數(shù)

typeid的主要作用就是讓用戶知道當(dāng)前的變量是什么類型的,比如以下代碼:

復(fù)制代碼 代碼如下:

#include <iostream>
#include <typeinfo>
using namespace std;
 
int main()
{
     short s = 2;
     unsigned ui = 10;
     int i = 10;
     char ch = 'a';
     wchar_t wch = L'b';
     float f = 1.0f;
     double d = 2;
 
     cout<<typeid(s).name()<<endl; // short
     cout<<typeid(ui).name()<<endl; // unsigned int
     cout<<typeid(i).name()<<endl; // int
     cout<<typeid(ch).name()<<endl; // char
     cout<<typeid(wch).name()<<endl; // wchar_t
     cout<<typeid(f).name()<<endl; // float
     cout<<typeid(d).name()<<endl; // double
 
     return 0;
}


對(duì)于C++支持的內(nèi)建類型,typeid能完全支持,我們通過調(diào)用typeid函數(shù),我們就能知道變量的信息。對(duì)于我們自定義的結(jié)構(gòu)體,類呢?

 

 

復(fù)制代碼 代碼如下:

#include <iostream>
#include <typeinfo>
using namespace std;
 
class A
{
public:
     void Print() { cout<<"This is class A."<<endl; }
};
 
class B : public A
{
public:
     void Print() { cout<<"This is class B."<<endl; }
};
 
struct C
{
     void Print() { cout<<"This is struct C."<<endl; }
};
 
int main()
{
     A *pA1 = new A();
     A a2;
 
     cout<<typeid(pA1).name()<<endl; // class A *
     cout<<typeid(a2).name()<<endl; // class A
 
     B *pB1 = new B();
     cout<<typeid(pB1).name()<<endl; // class B *
 
     C *pC1 = new C();
     C c2;
 
     cout<<typeid(pC1).name()<<endl; // struct C *
     cout<<typeid(c2).name()<<endl; // struct C
 
     return 0;
}

 

是的,對(duì)于我們自定義的結(jié)構(gòu)體和類,tpyeid都能支持。在上面的代碼中,在調(diào)用完typeid之后,都會(huì)接著調(diào)用name()函數(shù),可以看出typeid函數(shù)返回的是一個(gè)結(jié)構(gòu)體或者類,然后,再調(diào)用這個(gè)返回的結(jié)構(gòu)體或類的name成員函數(shù);其實(shí),typeid是一個(gè)返回類型為type_info類型的函數(shù)。那么,我們就有必要對(duì)這個(gè)type_info類進(jìn)行總結(jié)一下,畢竟它實(shí)際上存放著類型信息。

type_info類

去掉那些該死的宏,在Visual Studio 2012中查看type_info類的定義如下:

復(fù)制代碼 代碼如下:

class type_info
{
public:
    virtual ~type_info();
    bool operator==(const type_info& _Rhs) const; // 用于比較兩個(gè)對(duì)象的類型是否相等
    bool operator!=(const type_info& _Rhs) const; // 用于比較兩個(gè)對(duì)象的類型是否不相等
    bool before(const type_info& _Rhs) const;
 
    // 返回對(duì)象的類型名字,這個(gè)函數(shù)用的很多
    const char* name(__type_info_node* __ptype_info_node = &__type_info_root_node) const;
    const char* raw_name() const;
private:
    void *_M_data;
    char _M_d_name[1];
    type_info(const type_info& _Rhs);
    type_info& operator=(const type_info& _Rhs);
    static const char * _Name_base(const type_info *,__type_info_node* __ptype_info_node);
    static void _Type_info_dtor(type_info *);
};

 

在type_info類中,復(fù)制構(gòu)造函數(shù)和賦值運(yùn)算符都是私有的,同時(shí)也沒有默認(rèn)的構(gòu)造函數(shù);所以,我們沒有辦法創(chuàng)建type_info類的變量,例如type_info A;這樣是錯(cuò)誤的。那么typeid函數(shù)是如何返回一個(gè)type_info類的對(duì)象的引用的呢?我在這里不進(jìn)行討論,思路就是類的友元函數(shù)。

typeid函數(shù)的使用

typeid使用起來是非常簡(jiǎn)單的,常用的方式有以下兩種:

1.使用type_info類中的name()函數(shù)返回對(duì)象的類型名稱

就像上面的代碼中使用的那樣;但是,這里有一點(diǎn)需要注意,比如有以下代碼:

復(fù)制代碼 代碼如下:

#include <iostream>
#include <typeinfo>
using namespace std;
 
class A
{
public:
     void Print() { cout<<"This is class A."<<endl; }
};
 
class B : public A
{
public:
     void Print() { cout<<"This is class B."<<endl; }
};
 
int main()
{
     A *pA = new B();
     cout<<typeid(pA).name()<<endl; // class A *
     cout<<typeid(*pA).name()<<endl; // class A
     return 0;
}

 

我使用了兩次typeid,但是兩次的參數(shù)是不一樣的;輸出結(jié)果也是不一樣的;當(dāng)我指定為pA時(shí),由于pA是一個(gè)A類型的指針,所以輸出就為class A *;當(dāng)我指定*pA時(shí),它表示的是pA所指向的對(duì)象的類型,所以輸出的是class A;所以需要區(qū)分typeid(*pA)和typeid(pA)的區(qū)別,它們兩個(gè)不是同一個(gè)東西;但是,這里又有問題了,明明pA實(shí)際指向的是B,為什么得到的卻是class A呢?我們?cè)诳聪乱欢未a:

復(fù)制代碼 代碼如下:

#include <iostream>
#include <typeinfo>
using namespace std;
 
class A
{
public:
     virtual void Print() { cout<<"This is class A."<<endl; }
};
 
class B : public A
{
public:
     void Print() { cout<<"This is class B."<<endl; }
};
 
int main()
{
     A *pA = new B();
     cout<<typeid(pA).name()<<endl; // class A *
     cout<<typeid(*pA).name()<<endl; // class B
     return 0;
}

 

好了,我將Print函數(shù)變成了虛函數(shù),輸出結(jié)果就不一樣了,這說明什么?這就是RTTI在搗鬼了,當(dāng)類中不存在虛函數(shù)時(shí),typeid是編譯時(shí)期的事情,也就是靜態(tài)類型,就如上面的cout<<typeid(*pA).name()<<endl;輸出class A一樣;當(dāng)類中存在虛函數(shù)時(shí),typeid是運(yùn)行時(shí)期的事情,也就是動(dòng)態(tài)類型,就如上面的cout<<typeid(*pA).name()<<endl;輸出class B一樣,關(guān)于這一點(diǎn),我們?cè)趯?shí)際編程中,經(jīng)常會(huì)出錯(cuò),一定要謹(jǐn)記。

2.使用type_info類中重載的==和!=比較兩個(gè)對(duì)象的類型是否相等

這個(gè)會(huì)經(jīng)常用到,通常用于比較兩個(gè)帶有虛函數(shù)的類的對(duì)象是否相等,例如以下代碼:

復(fù)制代碼 代碼如下:

#include <iostream>
#include <typeinfo>
using namespace std;
 
class A
{
public:
     virtual void Print() { cout<<"This is class A."<<endl; }
};
 
class B : public A
{
public:
     void Print() { cout<<"This is class B."<<endl; }
};
 
class C : public A
{
public:
     void Print() { cout<<"This is class C."<<endl; }
};
 
void Handle(A *a)
{
     if (typeid(*a) == typeid(A))
     {
          cout<<"I am a A truly."<<endl;
     }
     else if (typeid(*a) == typeid(B))
     {
          cout<<"I am a B truly."<<endl;
     }
     else if (typeid(*a) == typeid(C))
     {
          cout<<"I am a C truly."<<endl;
     }
     else
     {
          cout<<"I am alone."<<endl;
     }
}
 
int main()
{
     A *pA = new B();
     Handle(pA);
     delete pA;
     pA = new C();
     Handle(pA);
     return 0;
}

 

這是一種用法,呆會(huì)我再總結(jié)如何使用dynamic_cast來實(shí)現(xiàn)同樣的功能。

dynamic_cast的內(nèi)幕

在這篇《static_cast、dynamic_cast、const_cast和reinterpret_cast總結(jié)》的文章中,也介紹了dynamic_cast的使用,對(duì)于dynamic_cast到底是如何實(shí)現(xiàn)的,并沒有進(jìn)行說明,而這里就要對(duì)于dynamic_cast的內(nèi)幕一探究竟。首先來看一段代碼:

 

復(fù)制代碼 代碼如下:

#include <iostream>
#include <typeinfo>
using namespace std;
 
class A
{
public:
     virtual void Print() { cout<<"This is class A."<<endl; }
};
 
class B
{
public:
     virtual void Print() { cout<<"This is class B."<<endl; }
};
 
class C : public A, public B
{
public:
     void Print() { cout<<"This is class C."<<endl; }
};
 
int main()
{
     A *pA = new C;
     //C *pC = pA; // Wrong
     C *pC = dynamic_cast<C *>(pA);
     if (pC != NULL)
     {
          pC->Print();
     }
     delete pA;
}

 

在上面代碼中,如果我們直接將pA賦值給pC,這樣編譯器就會(huì)提示錯(cuò)誤,而當(dāng)我們加上了dynamic_cast之后,一切就ok了。那么dynamic_cast在后面干了什么呢?

dynamic_cast主要用于在多態(tài)的時(shí)候,它允許在運(yùn)行時(shí)刻進(jìn)行類型轉(zhuǎn)換,從而使程序能夠在一個(gè)類層次結(jié)構(gòu)中安全地轉(zhuǎn)換類型,把基類指針(引用)轉(zhuǎn)換為派生類指針(引用)。我在《COM編程——接口的背后》這篇博文中總結(jié)的那樣,當(dāng)類中存在虛函數(shù)時(shí),編譯器就會(huì)在類的成員變量中添加一個(gè)指向虛函數(shù)表的vptr指針,每一個(gè)class所關(guān)聯(lián)的type_info object也經(jīng)由virtual table被指出來,通常這個(gè)type_info object放在表格的第一個(gè)slot。當(dāng)我們進(jìn)行dynamic_cast時(shí),編譯器會(huì)幫我們進(jìn)行語法檢查。如果指針的靜態(tài)類型和目標(biāo)類型相同,那么就什么事情都不做;否則,首先對(duì)指針進(jìn)行調(diào)整,使得它指向vftable,并將其和調(diào)整之后的指針、調(diào)整的偏移量、靜態(tài)類型以及目標(biāo)類型傳遞給內(nèi)部函數(shù)。其中最后一個(gè)參數(shù)指明轉(zhuǎn)換的是指針還是引用。兩者唯一的區(qū)別是,如果轉(zhuǎn)換失敗,前者返回NULL,后者拋出bad_cast異常。對(duì)于在typeid函數(shù)的使用中所示例的程序,我使用dynamic_cast進(jìn)行更改,代碼如下:

 

復(fù)制代碼 代碼如下:

#include <iostream>
#include <typeinfo>
using namespace std;
 
class A
{
public:
     virtual void Print() { cout<<"This is class A."<<endl; }
};
 
class B : public A
{
public:
     void Print() { cout<<"This is class B."<<endl; }
};
 
class C : public A
{
public:
     void Print() { cout<<"This is class C."<<endl; }
};
 
void Handle(A *a)
{
     if (dynamic_cast<B*>(a))
     {
          cout<<"I am a B truly."<<endl;
     }
     else if (dynamic_cast<C*>(a))
     {
          cout<<"I am a C truly."<<endl;
     }
     else
     {
          cout<<"I am alone."<<endl;
     }
}
 
int main()
{
     A *pA = new B();
     Handle(pA);
     delete pA;
     pA = new C();
     Handle(pA);
     return 0;
}

 

這個(gè)是使用dynamic_cast進(jìn)行改寫的版本。實(shí)際項(xiàng)目中,這種方法會(huì)使用的更多點(diǎn)。

總結(jié)

我在這里總結(jié)了RTTI的相關(guān)知識(shí),希望大家看懂了。這篇博文有點(diǎn)長(zhǎng),希望大家也耐心的看。總結(jié)了就會(huì)有收獲。

延伸 · 閱讀

精彩推薦
Weibo Article 1 Weibo Article 2 Weibo Article 3 Weibo Article 4 Weibo Article 5 Weibo Article 6 Weibo Article 7 Weibo Article 8 Weibo Article 9 Weibo Article 10 Weibo Article 11 Weibo Article 12 Weibo Article 13 Weibo Article 14 Weibo Article 15 Weibo Article 16 Weibo Article 17 Weibo Article 18 Weibo Article 19 Weibo Article 20 Weibo Article 21 Weibo Article 22 Weibo Article 23 Weibo Article 24 Weibo Article 25
主站蜘蛛池模板: 久久久久久久国产毛片 | 在线一区观看 | 免费观看av电影 | 精品久久精品 | 在线中文字幕视频 | 99热在线观看免费 | 国产精品免费av | 国产亚洲精品一区二区 | 成人午夜网站 | 色视频www在线播放国产人成 | 欧美日本一区二区三区 | 亚洲免费精品 | 国产精品视频一区二区三区不卡 | 日韩一区精品 | 私人毛片免费高清视频 | 成人aⅴ视频 | 成人精品一区二区 | 精品国产一区二区三区av性色 | 91影院在线观看 | 日韩欧美在线一区二区 | 久久夜夜 | 91av在线播放 | 欧美人成在线视频 | 成人三级视频 | 四虎久久 | 伊人短视频 | 99视频在线免费观看 | 黄色一级片一级片 | 欧美精品一区二区三区四区五区 | 在线中文视频 | 欧美精品一区在线 | 欧美一级二级视频 | 夜久久| 国产精品免费av | 色噜噜狠狠狠综合曰曰曰 | 国产精品久久久久久久久久新婚 | 99视频在线| 免费一区二区 | 亚洲国产精品一区 | 久久久无码精品亚洲日韩按摩 | 欧美成人免费在线视频 |