繁体   English   中英

使用typeid获取派生类的名称

[英]Using typeid to get name of derived class

我正在创建一个资源管理器,它接受从类Resource派生的类。 我的问题是typeid(..)。name()返回错误的类名。

我想将像Texture这样的资源添加到地图中,如下所示:

typedef std::unordered_map<std::string, Resource*> ResourceMap;

我希望'class + counter'的名称是Resource的字符串/名称。 不幸的是,一切都被称为P8Resource因为这些类派生自'资源'。 确实是一个不合时宜的困境,但是typeid必须知道texture是纹理,而不是资源。

class Resource {}; // abstract

class Texture : public Resource {};

Resource *texture = new Texture();
Texture *texture2 = new Texture();

typeid(texture).name(); // yields 'Resource'
typeid(texture2).name(); // yields 'Texture'

如何在不使用类型转换的情况下使第一个typeid语句产生'Texture'?

指针的typeid将始终是声明的类型,因为这是指针本身的真实类型。 要知道指针指向的对象的实际类型,您需要取消引用指针以获取实际类型: http//ideone.com/FYmp79

#include <iostream>
#include <typeinfo>
using namespace std;

struct Resource {
    virtual ~Resource() = default;
};

struct Texture : Resource {};

int main() {
    Resource *resource = new Resource;
    Resource *texture = new Texture;

    cout << typeid(*resource).name() << endl; // yields 'Resource'
    cout << typeid(*texture).name() << endl; // yields 'Texture'
    return 0;
}

编辑:正如其他人所说,你需要使类多态来获取运行时类型信息。

我的问题是typeid(..)。name()返回错误的类名。

typeid(...).name()仅用于调试或记录目的。 正如http://en.cppreference.com/w/cpp/types/type_info/name所说:

不给出任何保证,特别是返回的字符串对于几种类型可以是相同的,并且在相同程序的调用之间改变。

至于你的问题,

如何在不使用类型转换的情况下使第一个typeid语句产生'Texture'?

最安全,最简单和最正确的方法是向Resource添加您自己的虚拟名称功能:

virtual std::string name() const = 0;

然后在每个子类中重写它以返回类的名称。

首先, typeid只能为多态类类型的值提供动态运行时类型标识。 你的课程不是多态的。 您需要在基类中至少有一个虚方法才能“激活” typeid的动态行为。

其次,为了使用typeid来确定多态对象的动态类型,必须将它应用于对象本身 ,而不是指向对象的指针(如代码中所示)。

第三, name()返回的值并不重要,不能用于任何实际目的。 形式上, name()每次只能返回一个空字符串。 您必须使用(并比较) type_info对象本身来进行运行时类型识别。

如果表达式是多态类对象的glvalue,则typeid运算符只能返回表达式的动态类型

如果一个类直接或在其一个基础中定义至少一个虚拟成员函数,则该类是多态的

由于您的Resource类和派生类不满足此要求,因此typeid运算符只能访问静态类型

要解决这个问题,并在尝试delete指向此类资源的指针时遇到的问题,请将析构函数设置为virtual。

如果您使用的是Qt库,则可以使用元对象来区分资源实例。

class Resource : public QObject {
    Q_OBJECT

}; // abstract

class Texture : public Resource {
    Q_OBJECT
};

Resource *texture = new Texture();
Resource *resource = new Resource();

texture ->metaObject()->className(); // yields 'Texture'
resource ->metaObject()->className(); // yields 'Resource'

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM