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;
}
Typeinfo how to get the name/id of the class in a polymorphic collection?
typeid
to provide the dynamic type. Your classes are not polymorphic, so you would get the static type.typeid
to a pointer gives you the type info of the pointer type rather than type of the pointed object.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.
The output you are seeing is caused by the fact that the u
variable is auto
deduced to always be a std::unique_ptr<Base>
type.
One way of fixing this is to add virtual
members to your classes that return the typeid
of their respective this
pointers. Then, each call to that function on the u
pointer will call the actual derived 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;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With