C++ typeid關鍵字詳解

2021-02-20 CPP開發者

(給CPP開發者加星標,提升C/C++技能)

https://blog.csdn.net/gatieme/article/details/50947821【導讀】:本文主要介紹C++如何實現運行時期的類型判斷,並且較為深入的討論了具體源碼的實現,感興趣的同學一起和小編學習吧。

以下是正文

typeid關鍵字


注意:typeid是操作符,不是函數。這點與sizeof類似)。

運行時獲知變量類型名稱,可以使用。

需要注意不是所有編譯器都輸出」int」、」float」等之類的名稱,對於這類的編譯器可以這樣使用。

int ia = 3;if(typeid(ia) == typeid(int)){    cout <<"int" <<endl;}

RTTI(Run-Time Type Identification)-運行時類型識別

在揭開typeid神秘面紗之前,我們先來了解一下RTTI(Run-Time Type Identification,運行時類型識別),它使程序能夠獲取由基指針或引用所指向的對象的實際派生類型,即允許「用指向基類的指針或引用來操作對象」的程序能夠獲取到「這些指針或引用所指對象」的實際派生類型。

在C++中,為了支持RTTI提供了兩個操作符:dynamic_cast和typeid。

dynamic_cast允許運行時刻進行類型轉換,從而使程序能夠在一個類層次結構中安全地轉化類型,與之相對應的還有一個非安全的轉換操作符static_cast,因為這不是本文的討論重點,所以這裡不再詳述,感興趣的可以自行查閱資料。

typeid是C++的關鍵字之一,等同於sizeof這類的操作符。typeid操作符的返回結果是名為type_info的標準庫類型的對象的引用(在頭文件typeinfo中定義,稍後我們看一下vs和gcc庫裡面的源碼),它的表達式有下圖兩種形式。

實現機制與使用技巧type_info類對象類別判別對象類別判別分析

如果表達式的類型是類類型且至少包含有一個虛函數,則typeid操作符返回表達式的動態類型,需要在運行時計算;


否則,typeid操作符返回表達式的靜態類型,在編譯時就可以計算。

ISO C++標準並沒有確切定義type_info,它的確切定義編譯器相關的,但是標準卻規定了其實現必需提供如下四種操作(在之後的章節中我會來分析type_info類文件的源碼)。

運算描述t1 == t2如果兩個對象t1和t2類型相同,則返回true;否則返回falset1 != t2如果兩個對象t1和t2類型不同,則返回true;否則返回falset.name()返回類型的C-style字符串,類型名字用系統相關的方法產生1t1.before(t2)返回指出t1是否出現在t2之前的bool值

type_info類提供了public虛 析構函數,以使用戶能夠用其作為基類。它的默認構造函數和拷貝構造函數及賦值操作符都定義為private,所以不能定義或複製type_info類型的對象。程序中創建type_info對象的唯一方法是使用typeid操作符(由此可見,如果把typeid看作函數的話,其應該是type_info的 友元)。

type_info的name成員函數返回C-style的字符串,用來表示相應的類型名,但務必注意這個返回的類型名與程序中使用的相應類型名並不一定一致(往往如此,見後面的程序),這具體由編譯器的實現所決定的,標準只要求實現為每個類型返回唯一的字符串。


type_info類原始碼

使用sudo find / -name typeinfo.h來查找源碼。

#ifndef _TYPEINFO#define _TYPEINFO
#include <exception>
namespace std {
class type_info { public:
virtual ~type_info(); { return __name[0] == '*' ? __name + 1 : __name; }

bool before(const type_info& __arg) const { return __name < __arg.__name; }
bool operator==(const type_info& __arg) const { return __name == __arg.__name; }
bool operator!=(const type_info& __arg) const { return !operator==(__arg); }
virtual bool __is_pointer_p() const;
virtual bool __is_function_p() const;
protected: const char *__name;
explicit type_info(const char *__n): __name(__n) { }
private: type_info& operator=(const type_info&); type_info(const type_info&); };
} #endif

示例1-基本數據類型

下表列出了使用typeid操作符的表達式的值。

int a;double b;char * c;long d;

運算描述typeid(a) == typeid(int)truetypeid(a) == typeid(float)falsetypeid(a) == typeid(int *)falsetypeid(b) == typeid(double)truetypeid(b) == typeid(float)falsetypeid(b) == typeid(long double)falsetypeid(c) == typeid(char *)truetypeid(c) == typeid(char)falsetypeid(c) == typeid(string)falsetypeid(d) == typeid(long)truetypeid(d) == typeid(int)false

操作符typeid返回的是一個type_info類(用於描述數據類型的一個系統類)對象的引用。這個操作符可以用於表達式和類型名(包括自定的數據類型,比如類)。

示例2-類對象
class base{public :    void m(){cout<<"base"<<endl;}};class derived : public base{public:    void m(){cout<<"derived"<<endl;}};

假設我們根據例2中定義的兩個類來定義如下指針:

下表將給出使用typeid操作符的結果。

運算描述typeid(p) == typeid(base*)truetypeid(p) == typeid(derived*)falsetypeid(*p) == typeid(base)truetypeid(*p) == typeid(derived)false

對於表達式typeid(p),同樣,因為p是base*類型的指針,因此typeid(p) == typeid(base*)為真,而typeid(p) == typeid(derived*)為假。而對於表達式typeid(*p),由於此時的基類不具有多態性,因而*p將會採用編譯期類型來計算,編譯期*p是base對象,因此表達式typeid(*p) == typeid(derived)為假,typeid(*p) == typeid(base)為真。

示例3-帶虛函數的基類
class base{public :    virtual void m(){cout<<"base"<<endl;}};class derived : public base{public:    void m(){cout<<"derived"<<endl;}};

假設我們如本例所示定義了兩個類base類和derived類,基於這兩個類定義,我們定義指針如下:

下表將給出使用typeid操作符的結果。

運算描述typeid(p) == typeid(base*)truetypeid(p) == typeid(derived*)falsetypeid(*p) == typeid(base)falsetypeid(*p) == typeid(derived)true

對於表達式typeid(p),因為p是base*類型的指針,因此typeid(p) == typeid(base*)為真,而typeid(p) == typeid(derived*)為假。而對於表達式typeid(*p),因為base類具有多態性,因而在計算typeid(*p)時會根據運行時p所指向的實際類型去計算,而本例中p指向的是派生類對象,因此表達式typeid(*p) == typeid(derived)為真,typeid(*p) == typeid(base)為假。

異常處理bad_typeid
  class bad_typeid : public exception   {  public:    bad_typeid () throw() { }
virtual ~bad_typeid() throw();
virtual const char* what() const throw(); };}

參照

【C++】typeinfo.h

C++中的typeid關鍵字

- EOF -

關於 C++ typeid關鍵字,歡迎在評論中和我探討。覺得文章不錯,請點讚和在看支持我繼續分享好文。謝謝!

關注『CPP開發者』

看精選C++技術文章 . 加C++開發者專屬圈子

↓↓↓

點讚和在看就是最大的支持❤️

相關焦點

  • C++11特性:decltype關鍵字
    作者:melonstreet 連結:https://www.cnblogs.com/QG-whz/p/4952980.htmldecltype簡介我們之前使用的typeidRTTI機制為每一個類型產生一個type_info類型的數據,而typeid查詢返回的變量相應type_info數據,通過name成員函數返回類型的名稱。同時在C++11中typeid還提供了hash_code這個成員函數,用於返回類型的唯一哈希值。RTTI會導致運行時效率降低,且在泛型編程中,我們更需要的是編譯時就要確定類型,RTTI並無法滿足這樣的要求。
  • C++ explicit 關鍵字詳解
    以下是正文explicit關鍵字的作用explicit關鍵字在寫程序時使用的次數較少,但是仔細觀察會發現,在C++標準庫中的相關類聲明中explicit出現的頻率是很高的,那麼explicit關鍵字到底有什麼作用呢?接下來我就為大家一一解答。
  • C/C++中常用的編程關鍵字
    關鍵字作用:關鍵字是C++中預先保留的單詞(標識符)在定義變量或者常量時候,不要用關鍵字C++關鍵字如下:20. export為了訪問其他編譯單元(如另一代碼文件)中的變量或對象,對普通類型(包括基本數據類、結構和類),可以利用關鍵字 extern,來使用這些變量或對象時;但是對模板類型,則必須在定義這些模板類對象和模板函數時,使用標準 C++ 新增加的關鍵字 export(導出)。
  • C++ initializer_list 詳解
    有了initializer_list之後,對於STL的container的初始化就方便多了,比如以前初始化一個vector需要這樣:std::vector v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);而現在c++
  • C++、java 和 C 的區別
    一、基礎類型c++:** java:** C#:1.以java為準,c++裡面的int short long 像這樣的整型 一般都有unsigned 和signed的區分 ,這個跟java和c# 的區別比較大,但c#裡面有unit ulong ushort 這三種就相當於c++的修飾詞unsigned,當c++李明的變量類型定義unsigned,就默認是整數。
  • 九大程式語言優缺點第四期:c++
    C++:c++誕生於1983年,緊隨c語言的步伐,c++是C語言的超集,大家所知道的C語言是面向過程的,java是面向對象的,那麼C語言為了面向對象,所以誕生出現在大家所熟知的c++,被廣泛視為大規模應用構建軟體。
  • C++ vector詳解
    以下是正文前言本文mark了vector的一些接口,介紹了vector中的對內存和對象的管理詳解請見cppreference-vector。gt; fourth (third); int myints[] = {16,2,77,29}; std::vector<int> fifth (myints, myints + sizeof(myints) / sizeof(int) );列表初始化可以使用c++
  • 那些容易犯錯的c++保留字
    本文首發 | 公眾號:lunvey目前正在學習vc++6.0開發,而這裡面使用的是c++98標準。
  • Explicit,一個容易被忽視的關鍵字
    在C++的諸多關鍵字中,Explicit(顯式)作為一個具有相當實力卻又很低調的選手,很容易被我們忽視。
  • 【專業技術】C++ RTTI及「反射」技術
    每每涉及到處理異類容器和根基類層次(如 MFC)時,不可避免要對對象類型進行動態判斷,也就是動態類型的偵測。如何確定對象的動態類型呢?答案是使用內建的 RTTI 中的運算符:typeid 和 dynamic_cast。  首先讓我們來設計一個類層次,假設我們創建了某個處理文件的抽象基類。
  • C++typename的由來和用法
    這個關鍵字用於指出模板聲明(或定義)中的非獨立名稱(dependent names)是類型名,而非變量名。我們經常會這麼用 typename,這是一項C++程式語言的泛型編程(或曰「模板編程」)的功能,typename關鍵字用於引入一個模板參數。
  • C++中的static關鍵字的總結
    最近在備C++的課程,所以把在備課過程中遇到的問題進行了總結和梳理,先把C++中的static關鍵字的用法做以下總結。C++的static有兩種用法:面向過程程序設計中的static和面向對象程序設計中的static。前者應用於普通變量和函數,不涉及類;後者主要說明static在類中的作用。
  • C++超詳細筆記
    2.源文件擴展名:.cpp/.cc/.C/.cxx/.c++,最好用.cpp 3.頭文件:#include <iostream>  大多數標準庫頭文件都沒有.h後綴。結構 和C語言的不同:1)定義結構型變量時,可以省略struct關鍵字。2)結構內部可以定義函數——成員函數。
  • C++ 的幾個for 循環,範圍for語句
    例子:#include <iostream>using namespace std;int main(){ string str("this is a c++"); //每行輸出str中的一個字符 for(
  • c++之內存分配、命名空間、強制類型轉換學習總結
    一、C++動態內存分配:在學習c語言的時候,我們一般都是使用庫函數malloc()來進行內存的申請分配,然後使用庫函數free()來進行釋放申請到的內存;現在在c++裡面採用了另外一種內存申請的方法:c++中通過
  • c++11新特性,所有知識點都在這了!
    c++11新特性吧,你是怎麼回答的呢?auto & decltype關於C++11新特性,最先提到的肯定是類型推導,C++11引入了auto和decltype關鍵字,使用他們可以在編譯期就推導出變量或者表達式的類型,方便開發者編碼也簡化了代碼。
  • C++之字符串類學習總結
    一、回顧c語言對字符串的實現:一般我們在c語言要實現對字符串操作的話,一般是採用字符數組或者一組函數來實現的,為啥這樣做呢,那是因為c語言裡面根本就沒有字符串類型的關鍵字;而且c語言也支持自定義類型,所以更加無法獲得字符串類型為了解決這個問題,在c++中,引入了自定義類型,而且可以通過類來完成對字符串類型的定義。
  • C++與C中的const關鍵字有何差別?
    前言在《const關鍵字到底該怎麼用》一文中介紹了C語言中的const關鍵字,本文說說C++中的const關鍵字,它的大部分特點和C語言中的類似,所以本文主要針對不同之處
  • C/C++優勢究竟在哪裡?是什麼讓他們經久不衰?看看這個你就懂了
    相較於C語言,c++誕生於1983年,緊隨c語言的步伐,c++是C語言的超集,大家所知道的C語言是面向過程的,java是面向對象的,那麼C語言為了面向對象,所以誕生出現在大家所熟知的c++,被廣泛視為大規模應用構建軟體。
  • C++ 優先隊列priority_queue
    { cout << q.top() << endl; q.pop(); }}priority_queue<int> 默認構建的是一個大根堆,所以每次從頭取數據得到的是一個從大到小的隊列排序albert@home-pc:/mnt/c++