在 C++ 中使用 typeid 運算子

Jinku Hu 2023年10月12日
在 C++ 中使用 typeid 運算子

本文解釋並演示瞭如何在 C++ 中使用 typeid 運算子。

使用 typeid 運算子在 C++ 中檢索物件的型別名稱

你可以使用 typeid 運算子來檢索給定表示式或物件的型別資訊。它返回對 std::type_info 標準庫型別的引用,該型別在 <typeinfo> 標頭中定義。

std::type_info 物件具有成員函式 name,你可以利用它返回描述引數物件基礎型別的字串。請注意,由 typeid 檢索的型別資訊取決於實現。即,最常見的編譯器 gccclang 返回經過修改的名稱,如下一個程式碼示例所示。

Microsoft Visual C++ 等其他實現以更易讀的形式顯示資訊。儘管如此,請記住,你仍然可以學習識別由前一個實現顯示的內建型別的名稱。例如,int 物件返回一個 i 字元,而指向 int 物件的指標返回一個 Pi 字串。

#include <iostream>
#include <string>
#include <typeinfo>

using std::cin;
using std::cout;
using std::endl;
using std::string;

int main() {
  int i1 = 1234;
  string str1("arbitrary string");
  auto ptr = &i1;

  cout << "i1 type: " << typeid(i1).name() << '\n'
       << "str1 type: " << typeid(str1).name() << '\n'
       << "ptr type: " << typeid(ptr).name() << endl;

  const std::type_info& r1 = typeid(i1);
  cout << '\n' << "i1 type: " << r1.name() << '\n';

  return EXIT_SUCCESS;
}

輸出:

i1 type: i
str1 type: NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
ptr type: Pi

i1 type: i

另一方面,如果我們對物件的引用呼叫 typeid 命令,我們會發現檢索到的型別資訊並不總是準確的,有時太神祕而無法閱讀。以下示例顯示了第二次呼叫 typeid 運算子返回錯誤型別資訊的情況。

#include <iostream>
#include <string>
#include <typeinfo>

using std::cout;
using std::endl;

struct Base {};
struct Derived : Base {};

struct Base2 {
  virtual void foo() {}
};
struct Derived2 : Base2 {};

int main() {
  Derived d1;
  Base& b1 = d1;
  cout << "non-polymorphic base: " << typeid(b1).name() << '\n';

  Derived2 d2;
  Base2& b2 = d2;
  cout << "polymorphic base: " << typeid(b2).name() << '\n';

  return EXIT_SUCCESS;
}

輸出:

non-polymorphic base: 4Base
polymorphic base: 8Derived2

可以使用 Boost TypeIndex 庫函式 type_id_with_cvr 更正此行為,該函式可以準確返回型別資訊。通常,當使用 typeid 操作符時,帶有 constvolatile&&& 修飾符的物件都會導致錯誤的型別資訊;因此,你應該更好地依賴 type_id_with_cvr 函式。

以下程式碼示例需要在系統上安裝 Boost 庫,並且 type_id_with_cvr 函式位於 boost::typeindex 名稱空間下。

#include <boost/type_index.hpp>
#include <iostream>
#include <string>
#include <typeinfo>

using boost::typeindex::type_id_with_cvr;
using std::cout;
using std::endl;

struct Base {};
struct Derived : Base {};

struct Base2 {
  virtual void foo() {}
};
struct Derived2 : Base2 {};

int main() {
  Derived d1;
  Base& b1 = d1;

  Derived2 d2;
  Base2& b2 = d2;

  cout << type_id_with_cvr<decltype(b1)>().pretty_name() << '\n';
  cout << type_id_with_cvr<decltype(b2)>().pretty_name() << '\n';

  return EXIT_SUCCESS;
}

輸出:

Base&
Base2&
作者: Jinku Hu
Jinku Hu avatar Jinku Hu avatar

DelftStack.com 創辦人。Jinku 在機器人和汽車行業工作了8多年。他在自動測試、遠端測試及從耐久性測試中創建報告時磨練了自己的程式設計技能。他擁有電氣/ 電子工程背景,但他也擴展了自己的興趣到嵌入式電子、嵌入式程式設計以及前端和後端程式設計。

LinkedIn Facebook

相關文章 - C++ Operator