C++使用typeid获取类型信息type_info机制解析

这篇文章讨论一下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来识别是在编译期还是运行时计算,感兴趣的话可以试一下。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值