C++关键字-typeid
typeid是一个运算符,用来获取类型信息:
- 对于基本类型,类型信息指数据的类型。
- 对于类类型,类型信息指对象所属的类、所包含的成员、所在的继承关系等。
typeid运算符返回std::type_info
的引用(std::type_info在头文件typeinfo中定义)
如果表达式的类型是类类型且至少包含有一个虚函数,则typeid操作符返回表达式的动态类型,需要在运行时计算;否则,typeid操作符返回表达式的静态类型,在编译时就可以计算。
从上图可以发现,
- 提供了public虚析构函数,以使用户能够用其作为基类。
- 默认构造函数和拷贝构造函数及赋值操作符都定义为private,所以不能定义或复制type_info类型的对象。程序中创建type_info对象的唯一方法是使用typeid操作符。
- name成员函数返回C-style的字符串,用来表示相应的类型名,但务必注意这个返回的类型名与程序中使用的相应类型名并不一定一致,这具体由编译器的实现所决定的,标准只要求实现为每个类型返回唯一的字符串。
typeid用法:
#include <iostream>
#include <typeinfo>
#include <typeindex>
#include <cassert>
using namespace std;
struct Base {}; // 非多态
struct Derived : Base {};
struct Base2 { virtual void foo() {} }; // 多态
struct Derived2 : Base2 {};
int main()
{
Base b_1, b_2;
const std::type_info& type1 = typeid(b_1);
const std::type_info& type2 = typeid(b_2);
assert(&type1 == &type2); // 不保证
assert(type1 == type2); // 保证
assert(type1.hash_code() == type2.hash_code()); // 保证
assert(std::type_index(type1) == std::type_index(type2)); // 保证
int myint = 50;
std::string mystr = "string";
double *mydoublePtr = nullptr;
std::cout << "myint 的类型:" << typeid(myint).name() << '\n'
<< "mystr 的类型:" << typeid(mystr).name() << '\n'
<< "mydoublePtr 的类型:" << typeid(mydoublePtr).name() << '\n';
// std::cout << myint 是多态类型的泛左值表达式;求值
const std::type_info& r1 = typeid(std::cout << myint); // 副作用:打印 50
std::cout << '\n' << "std::cout<<myint 的类型:" << r1.name() << '\n';
// std::printf() 不是多态类型的泛左值表达式;不求值
const std::type_info& r2 = typeid(std::printf("%d\n", myint));
std::cout << "printf(\"%d\\n\",myint) 的类型:" << r2.name() << '\n';
// 非多态左值时是静态类型
Derived d1;
Base& b1 = d1;
std::cout << "非多态基类的引用:" << typeid(b1).name() << '\n';
Derived2 d2;
Base2& b2 = d2;
std::cout << "多态基类的引用:" << typeid(b2).name() << '\n';
}
一个可能的输出:
myint 的类型:i
mystr 的类型:NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
mydoublePtr 的类型:Pd
50
std::cout<<myint 的类型:So
printf("%d\n",myint) 的类型:i
非多态基类的引用:4Base
多态基类的引用:8Derived2