C++ 关键字typeid

转载网址:http://www.cppblog.com/smagle/archive/2010/05/14/115286.aspx

在揭开typeid神秘面纱之前,我们先来了解一下RTTI(Run-Time Type Identification,运行时类型识别),它使程序能够获取由基指针或引用所指向的对象的实际派生类型,即允许“用指向基类的指针或引用来操作对象”的程序能够获取到“这些指针或引用所指对象”的实际派生类型。在C++中,为了支持RTTI提供了两个操作符:dynamic_cast和typeid。
    dynamic_cast允许运行时刻进行类型转换,从而使程序能够在一个类层次结构中安全地转化类型,与之相对应的还有一个非安全的转换操作符static_cast,因为这不是本文的讨论重点,所以这里不再详述,感兴趣的可以自行查阅资料。下面就开始今天我们的话题:typeid。
  
   typeid是C++的关键字之一,等同于sizeof这类的操作符。typeid操作符的返回结果是名为type_info的标准库类型的对象的引用(在头文件typeinfo中定义,稍后我们看一下vs和gcc库里面的源码),它的表达式有下图两种形式。
  
  
   如果表达式的类型是类类型且至少包含有一个虚函数,则typeid操作符返回表达式的动态类型,需要在运行时计算;否则,typeid操作符返回表达式的静态类型,在编译时就可以计算。
    ISO C++标准并没有确切定义type_info,它的确切定义编译器相关的,但是标准却规定了其实现必需提供如下四种操作(在之后的章节中我会来分析type_info类文件的源码):

t1 == t2如果两个对象t1和t2类型相同,则返回true;否则返回false
t1 != t2如果两个对象t1和t2类型不同,则返回true;否则返回false
t.name()返回类型的C-style字符串,类型名字用系统相关的方法产生
t1.before(t2)返回指出t1是否出现在t2之前的bool值

    type_info类提供了public虚 析构函数,以使用户能够用其作为基类。它的默认构造函数和拷贝构造函数及赋值操作符都定义为private,所以不能定义或复制type_info类型的对象。程序中创建type_info对象的唯一方法是使用typeid操作符(由此可见,如果把typeid看作函数的话,其应该是type_info的 友元)。type_info的name成员函数返回C-style的字符串,用来表示相应的类型名,但务必注意这个返回的类型名与程序中使用的相应类型名并不一定一致(往往如此,见后面的程序),这具体由编译器的实现所决定的,标准只要求实现为每个类型返回唯一的字符串。

    上面的都是一些理论的东西,看不真切,下面将通过代码和图例来展示。

#include <iostream>
using namespace std;

class Base {};
class Derived: public Base {};

int main()
{
    Base b, *pb;
    pb = NULL;
    Derived d;

    cout << typeid(int).name() << endl
         << typeid(unsigned).name() << endl
         << typeid(long).name() << endl
         << typeid(unsigned long).name() << endl
         << typeid(char).name() << endl
         << typeid(unsigned char).name() << endl
         << typeid(float).name() << endl
         << typeid(double).name() << endl
         << typeid(string).name() << endl
         << typeid(Base).name() << endl
        << typeid(b).name()<<endl
         << typeid(pb).name()<<endl
         << typeid(Derived).name() << endl
         << typeid(d).name()<<endl
         << typeid(type_info).name() << endl;
        
    return 0;
}

我分别用MS的V8和GUN的GCC编译该段代码并运行,结果分别为下面的左右二图。

对比代码以及上面的文字描述,不知道各位是否已经有所明了(这里需要注意的是Base类的对象b和对象指针pb,他们的输出)。
    考虑到V8的输出很直观,所以我采用V8来做实验。下面对上面的代码稍微添加一点内容,如下:

Base *pb2 = dynamic_cast<Base *>(new Derived);
Base &b2 = d;
Base *pb3 = &d;
cout << typeid(pb2).name() <<endl//输出Base *
     << typeid(b2).name()<<endl //输出Base
     << typeid(pb3).name()<<endl//输出Base *
     << typeid(*pb3).name()<<endl;//输出Base

因为Base不包含虚函数,所以typeid的结果指出,表达式的类型是Base或Base *型,尽管他们的底层对象是Derived。即:当typeid操作符的操作数是不带有虚函数的类类型时,typeid操作符会指出操作数的类型,而不是底层对象的类型。
  
    下面在对Base函数做一个小小调整,为其加上一个虚函数,再看输出结果。

class Base {virtual void f(){}; };
/*...*/
cout << typeid(pb2).name() <<endl//输出Base *
     << typeid(b2).name()<<endl //输出Derived
     << typeid(pb3).name()<<endl//输出Base *
     << typeid(*pb3).name()<<endl;//输出Derived

这次Base含有虚函数,注意看结果,指针仍然是Base*的,尽管他们指向的是底层对象Derived,而这些Base对象的类型却是Derived的。
    因为指针pb3不是类类型,所以typeid就返回该指针pb3的指针类型Base *。而*pb3是一个类类型的表达式,而且该类带有虚函数,所以指出该pb3指向的底层对象的类型Derived。
   如果typeid操作符的操作数是至少包含一个虚拟函数的类类型时,并且该表达式是一个基类的应用,则typeid操作符指出底层对象的派生类类型。
    好了,文篇到此结束,留下几道小题目吧。

//采用V8环境

cout<<typeid(7.84).name()<<endl
   << typeid(Base*).name()<<endl
   << typeid(&pb3).name()<<endl;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/353641.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用Apache Camel进行负载平衡

在此示例中&#xff0c;我们将向您展示如何使用Apache Camel作为系统的负载平衡器。 在计算机世界中&#xff0c;负载均衡器是一种充当反向代理并在许多服务器之间分配网络或应用程序流量的设备。 负载平衡器用于增加容量&#xff08;并发用户&#xff09;和应用程序的可靠性。…

Java8-Guava实战示例

示例一&#xff1a; 跟示例三对比一下&#xff0c;尽量用示例三 List<InvoiceQueryBean> invoiceQueryBeanList new ArrayList<>(); List<String> invoices Lists.newArrayList(Iterators.transform(invoiceQueryBeanList.iterator(), new Function<Inv…

java项目构建部署包

博客分类&#xff1a; JAVA Java 工程在生产环境运行时&#xff0c;一般需要构建成一个jar&#xff0c;同时在运行时需要把依赖的jar添加到classpath中去&#xff0c;如果直接运行添加classpath很不方便&#xff0c;比较方便的是创建一个shell脚本。在公司项目中看到把工程代码…

不错的自学网站合集

一、网站类1、假期在家如何查找论文资料&#xff1f;只需登录中国图书馆http://t.cn/hYmDq&#xff08;需注册&#xff09;&#xff0c;即可免费下载各种期刊和学位论文2、全球免费开放的电子图书馆http://t.cn/h4hJUf3、给大家推荐个神网站&#xff0c;只要是外文书籍基本上都…

c++中关于字符串的读入——cin、getline、get、gtes(查询+思考+总结)

1、cin读入一个字符&#xff1a;char c;cin>>c;2、cin读入一个字符串&#xff1a;char s[10];cin >> s;&#xff08;c风格字符串&#xff09; string str;cin >> str;&#xff08;c的string&#xff09;3、cin.get()读入一个字符&#xff1a;char c;ccin.…

java文档注释和标题注释_Java注释:探究和解释

java文档注释和标题注释Java 5 SE的许多出色功能之一是Annotations构造的引入。 注释是一些标签&#xff0c;可以将其插入到程序源代码中&#xff0c;以使用某种工具对其进行处理并使其变得有意义。 注释处理工具通常使用&#xff08;Java 5 SE的&#xff09;Reflection API在J…

shell 脚本初步,启动可执行 jar 文件

可能很多同学在看到这篇文章的时候是第一次接触 shell 脚本。所以我们首先需要了解什么是 shell 脚本。在 Windows 里我们经常会看到一种扩展名为 .bat 的文件&#xff0c;它称为批处理文件。批处理文件的作用是把许多个命令放在一个文件里&#xff0c;当运行这个文件的时候就执…

使用Java创建DynamoDB表

在这篇文章中&#xff0c;我们将使用java方法在DynamoDB数据库上创建表。 在开始之前&#xff0c;我们需要安装本地dynamodb&#xff0c;因为我们要避免使用dynamodb的任何费用。 有一个以前的岗位上本地dynamodb。 如果您使用docker&#xff0c;则可以找到本地dynamodb映像&a…

表达式前后缀表达形式 [zz]

(2012-09-12 13:08:39) 转载▼标签&#xff1a; 杂谈 转自&#xff1a;http://blog.csdn.net/whatforever/article/details/673853835,15,,80,70,-,*,20,/ //后缀表达方式(((3515)*(80-70))/20&#xff09;25 //中缀表达方式 /,*,,35,15,-,80,70, 2…

引用:初探Sql Server 执行计划及Sql查询优化

引用:初探Sql Server 执行计划及Sql查询优化 原文:引用:初探Sql Server 执行计划及Sql查询优化初探Sql Server 执行计划及Sql查询优化 收藏MSSQL优化之————探索MSSQL执行计划作者&#xff1a;no_mIss最近总想整理下对MSSQL的一些理解与感悟&#xff0c;却一直没有心思和时间…

Cities

问题 C: Cities 时间限制: 1 Sec 内存限制: 128 MB提交: 87 解决: 61[提交][状态][讨论版][命题人:admin]题目描述 There are n cities in Byteland, and the ith city has a value ai. The cost of building a bidirectional road between two cities is the sum of their v…

spring观察者模式_Spring事件的观察者模式

spring观察者模式介绍 观察者模式的本质是“定义对象之间的一对多依赖关系&#xff0c;以便当一个对象改变状态时&#xff0c;其所有依赖关系都会被通知并自动更新”。 GoF。 观察者模式是发布/订阅模式的子集&#xff0c;它允许许多观察者对象查看事件。 可以在不同的情况下使…

Lombok,自动值和不可变项

我喜欢布兰登&#xff08;Brandon &#xff09;在博客文章中比较Project Lombok &#xff0c; AutoValue和Immutables的建议 &#xff0c;而这篇文章试图做到这一点。 我已经简要概述了Project Lombok &#xff0c; AutoValue和Immutables &#xff0c;但是这篇文章有所不同&am…

linux对于zombie的处理

(Linux基础)[僵尸进程处理] 今天在服务器上推送项目的时候&#xff0c;突然发现很卡。就用top查看了一下&#xff0c;果然此事不简单啊。 top - 10:39:16 up 20 days, 23:11, 2 users, load average: 1.13, 1.09, 1.03 Tasks: 204 total, 2 running, 196 sleeping, 1 sto…

POJ - 1847 Tram(dijkstra)

题意&#xff1a;有向图有N个点&#xff0c;当电车进入交叉口&#xff08;某点&#xff09;时&#xff0c;它只能在开关指向的方向离开。 如果驾驶员想要采取其他方式&#xff0c;他/她必须手动更换开关。当驾驶员从路口A驶向路口B时&#xff0c;他/她尝试选择将他/她不得不手动…

用interrupt()中断Java线程

Javathread 最近在学习Java线程相关的东西&#xff0c;和大家分享一下&#xff0c;有错误之处欢迎大家指正&#xff0e; 假如我们有一个任务如下&#xff0c;交给一个Java线程来执行&#xff0c;如何才能保证调用interrupt()来中断它呢&#xff1f; Java代码 class ATask imple…

activemq和jms_保证主题,JMS规范和ActiveMQ的消息传递

activemq和jms最近&#xff0c;一位客户要求我仔细研究ActiveMQ的“持久”消息的实现&#xff0c;它如何应用于主题以及在存在非持久订户的故障转移方案中会发生什么。 我已经了解到&#xff0c;JMS语义规定&#xff0c;即使面对消息代理提供程序故障&#xff0c;也只能保证主题…

JAVA分代收集机制详解

Java堆中是JVM管理的最大一块内存空间。主要存放对象实例。在JAVA中堆被分为两块区域&#xff1a;新生代&#xff08;young&#xff09;、老年代&#xff08;old&#xff09;。堆大小新生代老年代&#xff1b;&#xff08;新生代占堆空间的1/3、老年代占堆空间2/3&#xff09;新…

FizzBu​​zz Kata与Java流

在柔道练习仅几周之后&#xff0c;我的儿子感到无聊。 他抱怨说自己没有学任何东西&#xff0c;因为他一遍又一遍地做着同样的事情。 混淆学习和做新事物的不仅仅是幼儿。 例如&#xff0c;有多少软件开发人员通过执行kata或参加dojos来进行刻意练习的麻烦&#xff1f; 重复您…

高可用架构

转载于:https://www.cnblogs.com/138026310/p/9088341.html