Typeinfo 如何在多态集合中获取类的名称/ID?

now*_*wox 3 c++ polymorphism rtti typeid

在下面的例子中,我不希望 stdout : 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;
}
Run Code Online (Sandbox Code Playgroud)

有没有办法正确识别我的集合中有哪种实例?

编辑

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;
}
Run Code Online (Sandbox Code Playgroud)

eer*_*ika 6

Typeinfo 如何在多态集合中获取类的名称/ID?

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

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

typeid(*u).name()
Run Code Online (Sandbox Code Playgroud)

最后,您对可读类名的期望是错误的。std::type_info::name不能保证给你你为班级写的名字。结果是实现定义的,实际上您通常会得到类型的重整名称。没有获得可读名称的标准方法,但有实现定义的方法来对名称进行解构。

  • @nowox 就像这样`if (Foo* p =dynamic_cast&lt;Foo*&gt;(collection[1].get()))`。也就是说,“dynamic_cast”的大多数用途都可以通过使用虚函数来更好地实现。 (3认同)