目录
这篇文章讨论一下C++中typeid以及type_info的用法。
一.环境
windows11,VS2022
二.基础用法
1.需要明确一下typeid是操作符,不是函数,就像sizeof。
2.typeid的操作对象可以是变量,可以是类型,也可以是常量。
3.使用typeid可以获取到type_info类型的数据,顾名思义,就是数据类型信息。
4.使用typeid允许获取运行时的类型。
5.代码示例
#include<iostream>
#include<typeinfo>
class Demo
{
public:
Demo(void) = default;
~Demo(void) noexcept = default;
private:
};
int main(int argc, char* argv[])
{
int intVar = 10;
Demo demo;
auto& typeInfo = typeid(int);
const type_info& typeInfo2 = typeid(20);
std::cout << "typeInfo.name():" << typeInfo.name() << std::endl;
std::cout << "typeInfo2.name():" << typeInfo2.name() << std::endl;
std::cout << "typeid(Demo).name():" << typeid(Demo).name() << std::endl;
std::cout << "typeid(demo).name():" << typeid(demo).name() << std::endl;
if (typeid(int) == typeid(intVar))
{
std::cout << "==" << std::endl;
}
else
{
std::cout << "!=" << std::endl;
}
return 0;
}
很简单的代码,看一下运行的结果
type_info有多个成员函数以及支持的运算符,感兴趣可以打开IDE敲一敲。
三.编译期计算还是运行时计算
什么?上面不是有提到说允许使用typeid允许获取运行时的类型?这个问题不是很简单吗?当然是运行时了!那可不一定,写代码具体识别一下就知道了。
有个知识点我们都知道,那就是C++中模板的实例化是在编译期,所以模板参数需要在编译期确定。因此这里借助模板进行识别。
1.实验一
直接看代码
#include<iostream>
#include<typeinfo>
template<const type_info& typeInfo>
void Fun(void)
{
std::cout << "typeInfo.name()" << typeInfo.name() << std::endl;
}
int main(int argc, char* argv[])
{
int var = 10;
int& qVar = var;
int* pVar = &var;
Fun<typeid(int)>();
Fun<typeid(20)>();
Fun<typeid(var)>();
Fun<typeid(qVar)>();
Fun<typeid(pVar)>();
Fun<typeid(*pVar)>();
return 0;
}
执行的结果
代码能够正确编译并且得到预期结果,说明对于基础类型,typeid操作对象是类型/常量/对象/引用/指针/指针的解引用,都是在编译期计算好的。
2.实验二
直接看代码
#include<iostream>
#include<typeinfo>
template<const type_info& typeInfo>
void Fun(void)
{
std::cout << "typeInfo.name()" << typeInfo.name() << std::endl;
}
class DemoBase
{
public:
DemoBase(void) = default;
~DemoBase(void) noexcept = default;
};
class Demo : public DemoBase
{
public:
Demo(void) = default;
~Demo(void) noexcept = default;
};
int main(int argc, char* argv[])
{
Demo var;
DemoBase varBase;
Demo& qVar = var;
Demo* pVar = &var;
DemoBase& qVarBase = var;
DemoBase* pVarBase = &var;
Fun<typeid(Demo)>();
Fun<typeid(DemoBase)>();
Fun<typeid(var)>();
Fun<typeid(varBase)>();
Fun<typeid(qVar)>();
Fun<typeid(pVar)>();
Fun<typeid(*pVar)>();
Fun<typeid(qVarBase)>();
Fun<typeid(pVarBase)>();
Fun<typeid(*pVarBase)>();
return 0;
}
执行的结果
代码同样可以正确编译,说明对于不包含虚函数的自定义类型,typeid操作对象是类型/对象/引用/指针/指针的解引用,也都是在编译期计算的。
3.实验三
继续看代码
#include<iostream>
#include<typeinfo>
template<const type_info& typeInfo>
void Fun(void)
{
std::cout << "typeInfo.name()" << typeInfo.name() << std::endl;
}
class DemoBase
{
public:
DemoBase(void) = default;
virtual ~DemoBase(void) noexcept = default;
};
class Demo : public DemoBase
{
public:
Demo(void) = default;
virtual ~Demo(void) noexcept override = default;
};
int main(int argc, char* argv[])
{
Demo var;
DemoBase varBase;
Demo& qVar = var;
Demo* pVar = &var;
DemoBase& qVarBase = var;
DemoBase* pVarBase = &var;
Fun<typeid(Demo)>();
Fun<typeid(DemoBase)>();
Fun<typeid(var)>();
Fun<typeid(varBase)>();
Fun<typeid(qVar)>();
Fun<typeid(pVar)>();
Fun<typeid(*pVar)>();
Fun<typeid(qVarBase)>();
Fun<typeid(pVarBase)>();
Fun<typeid(*pVarBase)>();
return 0;
}
这个时候就不一样了啊,发现代码报错了,不能正确编译
可以看到报错的是引用和指针的解引用。
说明对于包含虚函数的自定义类型,typeid操作对象是类型/对象/指针,是在编译期运算的,typeid操作对象是引用/指针的解引用,是在运行时计算的。
什么,是不是对于包含虚函数的自定义类型,typeid不能那么写?放心,写法是对的,不信可以试一下不要写在模板里。
四.用法展示
展示一个看起来比较鸡肋的用法,代码
#include<iostream>
#include<typeinfo>
#include<memory>
class DemoBase
{
public:
DemoBase(void) = default;
void Fun(void)
{
std::cout << "typeid(*this).name():" << typeid(*this).name() << std::endl;
}
virtual ~DemoBase(void) noexcept = default;
};
class Demo : public DemoBase
{
public:
Demo(void) = default;
virtual ~Demo(void) noexcept override = default;
};
int main(int argc, char* argv[])
{
std::shared_ptr<DemoBase> p(new Demo());
p->Fun();
return 0;
}
执行结果
好像挺鸡肋对不对,但是即使真的鸡肋可能也会有一些合适的应用场景,感兴趣的话可以思考下。
五.其他
是不是也可以使用constexpr来识别是在编译期还是运行时计算,感兴趣的话可以试一下。
标签:info,typeid,DemoBase,类型信息,Demo,void,var,Fun From: https://blog.csdn.net/2401_85919417/article/details/140076903