typeinfo如何在多态的collection中得到class的name/id?

Typeinfo how to get the name/id of the class in a polymorphic collection?

在下面的示例中,我希望不是标准输出:Base Foo Bar,但我得到 P4Base P4Base P4Base:

#include <iostream>
#include <typeinfo>
#include <vector>
#include <memory>

class Base {};
class Foo : public Base {};
class Bar : public Base {};

using Collection = std::vector<std::unique_ptr<Base> >;

int main() {
    Collection collection;
    collection.push_back(std::make_unique<Base>());
    collection.push_back(std::make_unique<Foo>());
    collection.push_back(std::make_unique<Bar>());
    for (auto &u:collection)
        std::cout << typeid(u.get()).name() << std::endl;
}

有没有办法正确识别我的 collection 中的实例类型?

编辑

eerorika

建议后的工作示例
struct Base {virtual ~Base() = default;};
struct Foo : public Base {};
struct Bar : public Base {};

using Collection = std::vector<std::unique_ptr<Base> >;

int main() {
    Collection collection;
    collection.push_back(std::make_unique<Base>());
    collection.push_back(std::make_unique<Foo>());
    collection.push_back(std::make_unique<Bar>());
    for (auto &u:collection)
        std::cout << typeid(*u).name() << std::endl;
}

变量 var 的表达式 typeid(var).name() 在不同类型中应该是唯一的。但是,对于索引和一般区分用途,您应该使用 typeid(var).hash_code().

您看到的输出是由于 u 变量被 auto 推断为 总是std::unique_ptr<Base> 类型.

解决此问题的一种方法是将 virtual 成员添加到您的 class 中,即 return 各自 this 指针的 typeid。然后,在 u 指针上对该函数的每次调用都将调用 actual 派生的 class override:

class Base {
public:
    virtual const char* name() { return typeid(this).name(); }
};
class Foo : public Base {
public:
    const char* name() override { return typeid(this).name(); }
};
class Bar : public Base {
public:
    const char* name() override { return typeid(this).name(); }
};

using Collection = std::vector<std::unique_ptr<Base> >;

int main()
{
    Collection collection;
    collection.push_back(std::make_unique<Base>());
    collection.push_back(std::make_unique<Foo>());
    collection.push_back(std::make_unique<Bar>());
    for (auto& u : collection)
        std::cout << u->name() << std::endl;
    return 0;
}

Typeinfo how to get the name/id of the class in a polymorphic collection?

  • 首先,classes 必须是多态的,以便 typeid 提供动态类型。你的 classes 不是多态的,所以你会得到静态类型。
  • 其次,必须使用指向对象的左值而不是指针。将 typeid 应用于指针会为您提供指针类型的类型信息,而不是指向对象的类型。
  • 第三,你的程序的行为是未定义的,因为派生对象是通过非虚拟析构函数指向基的指针销毁的。

要修复第一点和第三点,请为基类提供一个虚拟析构函数。修复第二个:

typeid(*u).name()

最后,您对可读 class 名称的期望是错误的。 std::type_info::name 不能保证为您提供您为 class 编写的名称。结果是实现定义的,在实践中,您通常会得到类型的错位名称。没有获得可读名称的标准方法,但有实现定义的方法来分解名称。

有几个问题。

  1. u.get() 具有“指向 Base 的指针”类型。如果要打印对象本身的类型,请尝试 typeid(*u.get()).name().
  2. 如果您想要多态行为,请使用多态 类。这需要在Base中至少定义一个虚函数。无论如何,您需要定义一个虚拟析构函数才能正确删除对象。没有一个,程序有UB。
  3. name() returns 一个实现定义的字符串,所以你不能指望 Base Foo Bar。如果您解决其他问题,您可能会得到类似的东西。 Live demo.