C++中typeid的使用

2023-11-13

RTTI(Run-TimeType Information, 运行时类型信息),它提供了运行时确定对象类型的方法。在C++中,为了支持RTTI提供了两个操作符:dynamic_cast和typeid。

The typeid operator provides a program with the ability to retrieve the actual derived type of the object referred to by a pointer or a reference. The typeid operator requires run time type information (RTTI) to be generated, which must be explicitly specified at compile time through a compiler option. The typeid operator returns an lvalue of type const std::type_info that represents the type of expression expr.

typeid是C++的一个关键字,等同于sizeof这类操作符。typeid操作符的返回结果是名为type_info的标准库类型的对象的引用。type_info的name成员函数返回C-style的字符串。

如果表达式的类型是类类型且至少包含有一个虚函数,则typeid操作符返回表达式的动态类型,需要在运行时计算;否则,typeid操作符返回表达式的静态类型,在编译时就可以计算。

使用typeid时应注意:

(1)、typeid运算符允许在运行时确定对象的类型;

(2)、typeid的结果是const type_info&;

(3)、typeid运算符在应用于多态类类型的左值时执行运行时检查,其中对象的实际类型不能由提供的静态信息确定;

(4)、typeid也可在模板中使用以确定模板参数的类型;

(5)、typeid是操作符,不是函数,运行时获知变量类型名称;

(6)、要使用typeid,首先要确保编译器开启了运行时类型检查(RTTI)。

以下是测试代码:

#include "typeid.hpp"
#include <assert.h>
#include <iostream>
#include <string>
#include <typeinfo>
#include <vector>


int func(int a)
{
	return 0;
}

typedef int(*func_ptr)(int);
class Base { public: Base(){} };

int test_typeid1()
{
	char char_ = 'a';
	unsigned char uchar_ = 'b';
	short short_ = 2;
	unsigned short ushort_ = 3;
	int int_ = 1;
	unsigned int uint_ = 4;
	float float_ = 2.0;
	double double_ = 1.0;
	long long_ = 5;
	long long llong_ = 6;
	int array[10] = { 1};
	int* array_header = array;
	std::string string_;
	std::vector<int> int_vector;
	func_ptr f = func;
	Base Base_;
	Base* pBase_ = new Base;
	Base& Base__ = Base_;

	// 对于返回字符串的具体内容,与编译器有关
	std::cout << "char_ type: " << typeid(char_).name() << std::endl; // char_ type: char
	assert(typeid(char).name() == typeid(char_).name());
	
	std::cout << "uchar type: " << typeid(uchar_).name() << std::endl; // uchar type: unsigned char
	assert(typeid(unsigned char).name() == typeid(uchar_).name());
	
	std::cout << "short_ type: " << typeid(short_).name() << std::endl; // short_ type: short
	assert(typeid(short).name() == typeid(short_).name());
	
	std::cout << "ushort_ type: " << typeid(ushort_).name() << std::endl; // ushort_ type: unsigned short
	assert(typeid(unsigned short).name() == typeid(ushort_).name());

	std::cout << "int_ type: " << typeid(int_).name() << std::endl; // int_ type: int
	assert(typeid(int).name() == typeid(int_).name());
	
	std::cout << "uint_ type: " << typeid(uint_).name() << std::endl; // uint_ type: unsigned int
	assert(typeid(unsigned int).name() == typeid(uint_).name());
	
	std::cout << "float_ type: " << typeid(float_).name() << std::endl; // float_ type: float
	assert(typeid(float).name() == typeid(float_).name());

	std::cout << "double_ type: " << typeid(double_).name() << std::endl; // double_ type: double
	assert(typeid(double).name() == typeid(double_).name());

	std::cout << "long_ type: " << typeid(long_).name() << std::endl; // long_ type: long
	assert(typeid(long).name() == typeid(long_).name());

	std::cout << "llong_ type: " << typeid(llong_).name() << std::endl; // llong_ type: __int64
	assert(typeid(long long).name() == typeid(llong_).name());

	std::cout << "array[] type: " << typeid(array).name() << std::endl; // array[] type: int [10]
	assert(typeid(int [10]).name() == typeid(array).name());

	std::cout << "array_header type: " << typeid(array_header).name() << std::endl; // array_header type: int * __ptr64
	assert(typeid(int*).name() == typeid(array_header).name());
	
	std::cout << "string_ type: " << typeid(string_).name() << std::endl; // string_ type: class std::basic_string<char,struct std::char_traits<char>, class std::allocator<char>>
	assert(typeid(std::string).name() == typeid(string_).name());

	std::cout << "int_vector type: " << typeid(int_vector).name() << std::endl; // int_vector type: class std::vector<int,class std::allocator<int>>
	assert(typeid(std::vector<int>).name() == typeid(int_vector).name());

	std::cout << "f type: " << typeid(f).name() << std::endl; // f type : int(__cdecl*)(int)
	assert(typeid(int(*)(int)).name() == typeid(f).name());

	std::cout << "Base_ type: " << typeid(Base_).name() << std::endl; // Base_ type: class Base
	assert(typeid(class Base).name() == typeid(Base_).name());

	std::cout << "pBase_ type: " << typeid(pBase_).name() << std::endl; // pBase_ type: class Base * __ptr64
	assert(typeid(class Base*).name() == typeid(pBase_).name());

	std::cout << "Base__ type: " << typeid(Base__).name() << std::endl; // Base__ type: class Base
	assert(typeid(class Base).name() == typeid(Base__).name());

	delete pBase_;
	return 0;
}


// reference: http://en.cppreference.com/w/cpp/language/typeid
int test_typeid2()
{
	struct Base {}; // non-polymorphic
	struct Derived : Base {};

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

	int myint = 50;
	std::string mystr = "string";
	double *mydoubleptr = nullptr;

	std::cout << "myint has type: " << typeid(myint).name() << '\n' // myint has type: int
		<< "mystr has type: " << typeid(mystr).name() << '\n' // mystr has type: class std::basic_string<char, struct std::char_traits<char>, class std::allocator<char>>
		<< "mydoubleptr has type: " << typeid(mydoubleptr).name() << '\n'; // mydoubleptr has type: double * __ptr64

	// std::cout << myint is a glvalue expression of polymorphic type; it is evaluated
	const std::type_info& r1 = typeid(std::cout << myint); // 50
	std::cout << "std::cout<<myint has type : " << r1.name() << '\n'; // std::cout<<myint has type: class std::basic_ostream<char, struct std::char_traits<char>>

	// std::printf() is not a glvalue expression of polymorphic type; NOT evaluated
	const std::type_info& r2 = typeid(std::printf("%d\n", myint));
	std::cout << "printf(\"%d\\n\",myint) has type : " << r2.name() << '\n'; // printf(\"%d\\n\",myint) has type : int

	// Non-polymorphic lvalue is a static type
	Derived d1;
	Base& b1 = d1;
	std::cout << "reference to non-polymorphic base: " << typeid(b1).name() << '\n'; // reference to non-polymorphic base: struct 'int __cdecl test_typeid2(void)'::'2'::Base

	Derived2 d2;
	Base2& b2 = d2;
	std::cout << "reference to polymorphic base: " << typeid(b2).name() << '\n'; // reference to polymorphic base: struct 'int __cdecl test_typeid2(void)'::'3'::Derived2

	try {
		// dereferencing a null pointer: okay for a non-polymoprhic expression
		std::cout << "mydoubleptr points to " << typeid(*mydoubleptr).name() << '\n'; // mydoubleptr points to double
		// dereferencing a null pointer: not okay for a polymorphic lvalue
		Derived2* bad_ptr = NULL;
		std::cout << "bad_ptr points to...";  // bad_ptr points to... 
		std::cout << typeid(*bad_ptr).name() << '\n';
	}
	catch (const std::bad_typeid& e) {
		std::cout << " caught " << e.what() << '\n'; // caught Attempted a typeid of NULL pointer!
	}

	return 0;
}

///
// reference: https://msdn.microsoft.com/zh-cn/library/fyf39xec.aspx
template < typename T >
T max(T arg1, T arg2) {
	std::cout << typeid(T).name() << "s compared." << std::endl;
	return (arg1 > arg2 ? arg1 : arg2);
}

int test_typeid3()
{
	class Base {
	public:
		virtual void vvfunc() {}
	};

	class Derived : public Base {};

	Derived* pd = new Derived;
	Base* pb = pd;
	std::cout << typeid(pb).name() << std::endl;   //prints "class Base *" // class 'int __cdecl test_typeid3(void)'::'2'::Base * __ptr64
	std::cout << typeid(*pb).name() << std::endl;   //prints "class Derived" // class 'int __cdecl test_typeid3(void)'::'2'::Derived
	std::cout << typeid(pd).name() << std::endl;   //prints "class Derived *" // class 'int __cdecl test_typeid3(void)'::'2'::Derived * __ptr64
	std::cout << typeid(*pd).name() << std::endl;   //prints "class Derived" // class 'int __cdecl test_typeid3(void)'::'2'::Derived
	delete pd;

	float a = 1.2, b = 3.4;
	max(a, b); // floats compared

	return 0;
}

GitHubhttps://github.com/fengbingchun/Messy_Test

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++中typeid的使用 的相关文章

  • C++中的虚函数表介绍

    在C 语言中 当我们使用基类的引用或指针调用一个虚成员函数时会执行动态绑定 因为我们直到运行时才能知道到底调用了哪个版本的虚函数 所以所有虚函数都必须有定义 通常情况下 如果我们不使用某个函数 则无须为该函数提供定义 但是我们必须为每一个虚
  • C语言中的弱符号与强符号介绍

    弱符号 Weak symbol 是链接器 ld 在生成ELF Executable and Linkable Format 缩写为ELF 可执行和可链接格式 是一种用于可执行文件 目标文件 共享库和核心转储的标准文件格式 ELF文件有两种索
  • C++11中模板类std::enable_shared_from_this的使用

    C 11中的模板类template
  • C++中namespace detail或namespace internal的使用

    在很多开源代码中偶尔会使用名字为 detail 或 internal 的命名空间 如OpenCV的modules目录中 有些文件中使用了namespace detail 有些文件中使用了namespace internal 名为detail
  • 在Ubuntu 18.04上支持C++17的std::filesystem的方法

    在Ubuntu 18 04上通过命令sudo apt install gcc g 安装的gcc g 版本为7 5 此版本并不直接支持filesystem 如下图所示 Ubuntu 18 04上的g 7 5支持experimental的fil
  • C++11中std::future的使用

    C 11中的std future是一个模板类 std future提供了一种用于访问异步操作结果的机制 std future所引用的共享状态不能与任何其它异步返回的对象共享 与std shared future相反 std future r
  • C++11容器中新增加的emplace相关函数的使用

    C 11中 针对顺序容器 如vector deque list 新标准引入了三个新成员 emplace front emplace和emplace back 这些操作构造而不是拷贝元素 这些操作分别对应push front insert和p
  • C++11中头文件atomic的使用

    原子库为细粒度的原子操作提供组件 允许无锁并发编程 涉及同一对象的每个原子操作 相对于任何其他原子操作是不可分的 原子对象不具有数据竞争 data race 原子类型对象的主要特点就是从不同线程访问不会导致数据竞争 因此从不同线程访问某个原
  • C和C++安全编码笔记:文件I/O

    C和C 程序通常会对文件进行读写 并将此作为它们正常操作的一部分 不计其数的漏洞正是由这些程序与文件系统 其操作由底层操作系统定义 交互方式的不规则性而产生的 这些漏洞最常由文件的识别问题 特权管理不善 以及竞争条件导致 8 1 文件I O
  • log库spdlog简介及使用

    spdlog是一个开源的 快速的 仅有头文件的C 11 日志库 code地址在 https github com gabime spdlog 目前最新的发布版本为0 14 0 它提供了向流 标准输出 文件 系统日志 调试器等目标输出日志的能
  • 提高C++性能的编程技术笔记:多线程内存池+测试代码

    为了使多个线程并发地分配和释放内存 必须在分配器方法中添加互斥锁 全局内存管理器 通过new 和delete 实现 是通用的 因此它的开销也非常大 因为单线程内存管理器要比多线程内存管理器快的多 所以如果要分配的大多数内存块限于单线程中使用
  • Effective C++改善程序与设计的55个具体做法笔记

    Scott Meyers大师Effective三部曲 Effective C More Effective C Effective STL 这三本书出版已很多年 后来又出版了Effective Modern C More Effective
  • C++中vector的使用

    向量std vector是一种对象实体 能够容纳许多各种类型相同的元素 包括用户自定义的类 因此又被称为序列容器 与string相同 vector同属于STL Standard Template Library 中的一种自定义的数据类型 可
  • C++中nothrow的介绍及使用

    在C中 使用malloc等分配内存的函数时 一定要检查其返回值是否为 空指针 并以此作为检查内存操作是否成功的依据 这种Test for NULL代码形式是一种良好的编程习惯 也是编写可靠程序所必需的 在C 中new在申请内存失败时默认会抛
  • C/C++中#pragma once的使用

    在C C 中 为了避免同一个文件被include多次 有两种方式 一种是 ifndef方式 一种是 pragma once方式 在头文件的最开始加入 ifndef SOME UNIQUE NAME HERE define SOME UNIQ
  • C++/C++11中头文件iterator的使用

  • C++11中std::shared_future的使用

    C 11中的std shared future是个模板类 与std future类似 std shared future提供了一种访问异步操作结果的机制 不同于std future std shared future允许多个线程等待同一个共
  • 开源库jemalloc简介

    jemalloc是通用的malloc 3 实现 它强调避免碎片和可扩展的并发支持 它的源码位于https github com jemalloc jemalloc 最新稳定版本为5 2 1 glibc的内存分配算法是基于dlmalloc实现
  • C++17中utf-8 character literal的使用

    一个形如42的值被称作字面值常量 literal 这样的值一望而知 每个字面值常量都对应一种数据类型 字面值常量的形式和值决定了它的数据类型 由单引号括起来的一个字符称为char型字面值 双引号括起来的零个或多个字符则构成字符串型字面值 字
  • Linux下getopt函数的使用

    getopt为解析命令行参数函数 它是Linux C库函数 使用此函数需要包含系统头文件unistd h getopt函数声明如下 int getopt int argc char const argv const char optstri

随机推荐

  • 六、Pytest自动化测试框架 — Pytest预期失败

    文章内容有配套的 学习视频和笔记都放在了文章末尾 Pytest预期失败需要使用 pytest mark xfail 标记 1 pytest mark xfail 标记的作用 期望测试用例是失败的 但是会运行此测试用例 并且也不会影响其他测试
  • hive报错:return code 1 from org.apache.hadoop.hive.ql.exec.DDLTask. MetaException(message:Got exceptio

    根据网上搜的解决方案 基本都是说连接的mysql编码不对 改alter database hive character set latin1 但是依然报错 根据后半段报错 MetaException message Got exceptio
  • Linux用dd命令制作启动盘

    1 将U盘格式化成 FAT32 格式 按Ctrl R 打开cmd 输入diskpart 输入list disk select disk 1 输入clean 2 在windows 系统上找到Disk Management 选择disk 1 右
  • linux命令批量修改文件名称

    批量修改文件名称 剔除部分相同的内容 for name in ls a do mv name name x86 64 unknown linux gnu a done 解释说明 ls a 是改目录下所有的 a文件 mv 源文件名 替换文件名
  • Unity学习记录——粒子系统与流动效果

    Unity学习记录 粒子系统与流动效果 前言 本文是中山大学软件工程学院2020级3d游戏编程与设计的最终作业 编程题 粒子光环 1 概述 粒子系统在unity官网与老师课件中的概念定义如下 粒子系统 Unity 手册 一个粒子系统可以模拟
  • Python语言程序设计 最新测验题目汇总 嵩天老师

    测验1 Python基本语法元素 Hello World的条件输出 获得用户输入的一个整数 参考该整数值 打印输出 Hello World 要求 如果输入值是0 直接输出 Hello World 如果输入值大于0 以两个字符一行方式输出 H
  • 草根程序员转型做项目管理走过的点点滴滴之"经验总结"

    本篇总结主要以驻场团队的过往经验为基础开展 与其是较经验总结 称呼为过往会议更贴切 团队内部一次交流记录 随后会继续补充完善 1 沟通交流 a 交流的平等基因 不可怯场 把握一个平等的状态投入到沟通交流中去 b 交流的整段性 不要打断客户的
  • 2021年信息安全保研经历分享

    一 写在前面 1 基本信息 学校 排名 某双非学校 信息安全专业 成绩 综合均是rank1 英语 四级560 六级430 获奖 国家奖学金 蓝桥杯省一 几个校奖 项目 一个很水的校级大创 最终去向 东南网安 南京专硕 总的来说 我就是一个无
  • karma配置及使用

    karma配置及使用 一 定义 Karma不是测试框架 也不是断言库 Karma是一个测试工具 一个允许在多个真实浏览器中执行JavaScript代码的工具 为开发人员提供高效的测试环境 代码可能是设计在浏览器端执行的 在node环境下测试
  • qnx的汽车全液晶仪表-基于qnx系统的汽车仪表-车机系统开发

    如果你认为本系列文章对你有所帮助 请大家有钱的捧个钱场 点击此处赞助 赞助额0 1元起步 多少随意 声明 本文只用于个人学习交流 若不慎造成侵权 请及时联系我 立即予以改正 锋影 e mail 174176320 qq com QNX系统在
  • 3·15报道:“隔空盗刷”资金骗局曝出

    近些年顾客的网上购物等服务愈来愈多 许多犯罪分子根据 ETC卡禁止使用 快递丢失赔付 等骗术 哄骗顾客登陆诈骗网站对它进行行骗 3 15晚会视频表明 陈女士曾收到一条提醒她ETC卡已禁用短信 需登录网页开展签办 接着 陈女士点链接之后发现
  • vue.js——事件循环机制

    一 事件循环机制介绍 JS是单线程的语言 浏览器和Node js定义了各自的Event Loop 事件循环机制 则是用来解决异步问题 将程序分为 主线程 执行栈 与 Event Loop线程 主线程 自上而下依次执行同步任务 Event L
  • 毕业设计 - 基于java web的在线考试系统【源码+论文】

    文章目录 前言 一 项目设计 1 模块设计 2 基本功能 2 1 登录功能 2 2 系统答题 2 3 答题得分 2 4 错题解析 3 实现效果 二 部分源码 项目源码 前言 今天学长向大家分享一个 Java web 项目 可用于毕业设计 课
  • vue新一代的状态管理器之pinia

    Pinia 简介 Pinia 是 Vue 新一代的轻量级状态管理库 相当于 Vuex 也是 Vue 核心团队推荐的状态管理库 同时支持 Vue2 和 Vue3 未来很有可能替代 Vuex 比 Vuex 更容易上手 特性 Pinia 具有以下
  • 探索未来的人机交互方式

    在21世纪 人工智能 AI 已成为科技领域的重要焦点 特别是在 生成式AI 这个细分领域中 所谓的 生成式AI 是指能够创造 理解和生成各种形式内容的人工智能系统 本文将重点探讨 生成式AI 报告中的重点词汇或短语 为您解析它的潜力与未来
  • 线程池+CountDownLatch 处理大集合

    场景 有一个需求 首先从数据库中取出上千条数据 然后需要逐条对数据进行分析 例如分析情感 是否重复等多项分析 解决 将取出来的上千条 分批 多线程处理 public class CountDownLatchTest public stati
  • C++ bitset的用法实例

    C bitset的用法实例 一 bitset 二 代码 三 总结 一 bitset 顾名思义 bitset是位bit的set集合 是可以当做容器使用的一种数据结构 bitset提供了一些很实用的方法 能用来替代C语言的直接按位运算带来的不便
  • 毕设基于深度学习的以图搜图系统 matlab语言

    毕设基于深度学习的以图搜图系统 matlab语言 文章目录 毕设基于深度学习的以图搜图系统 matlab语言 前言 一 实验数据集准备 二 软件设计 1 以图搜纸皮 2 以图搜花 实验总结 前言 随着人工智能的不断发展 深度学习这门技术也越
  • NFT颓势已现:肝不起了,卷不动了

    白名单制度是时候变革了 作者 星球小花 出品 Odaily星球日报 ID o daily 前几天 一位朋友问我 几个月没关注 NFT 了 你们怎么还在抢 PFP 我也反驳了一番 现在有很多圈外流量涌入 巨头纷纷进场 应用遍地开花 不过仔细想
  • C++中typeid的使用

    RTTI Run TimeType Information 运行时类型信息 它提供了运行时确定对象类型的方法 在C 中 为了支持RTTI提供了两个操作符 dynamic cast和typeid The typeid operator pro