Search code examples
c++polymorphismrttitypeid

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


In the following example I would expect not stdout : Base Foo Bar, but I get 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;
}

Is there a way to properly identify which kind of instance I have in my collection?

EDIT

A Working example after the advice of 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;
}

Solution

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

    • Firstly, the classes must be polymorphic in order for typeid to provide the dynamic type. Your classes are not polymorphic, so you would get the static type.
    • Secondly, you must use an lvalue to the pointed object instead of a pointer. Applying typeid to a pointer gives you the type info of the pointer type rather than type of the pointed object.
    • Thirdy, the behaviour of your program is undefined because derived objects are destroyed through pointer to base with non-virtual destructor.

    To fix first and third point, provide a virtual destructor for the base. To fix second:

    typeid(*u).name()
    

    Lastly, your expectation of readable class names is misguided. std::type_info::name is not guaranteed to give you the name as you have written it for the class. The result is implementation defined, and in practice you typically get the mangled name of the type. There is no standard way to get a readable name, but there are implementation defined ways to demangle names.