Reputation: 29166
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;
}
Upvotes: 3
Views: 1247
Reputation: 238431
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.
Upvotes: 6
Reputation: 120079
There are several issues.
u.get()
has a type "pointer to Base". If you want to print the type of the object itself, try typeid(*u.get()).name()
.Base
. You need to define a virtual destructor anyway for correct behaviour of object deletion. Without one, the program has UB.name()
returns an implementation-defined string, so you cannot expect Base Foo Bar
. You might get something similar though if you fix the other problems. Live demo.Upvotes: 2
Reputation: 51894
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;
}
Upvotes: 4
Reputation: 2598
The expression typeid(var).name()
for variable var
should be unique among different types. However, for indexing and general distinguishing use you should use typeid(var).hash_code()
.
Upvotes: 1