I'm creating a resource manager that takes in classes derived from the class Resource
. My problem is that typeid(..).name() returns the wrong name of the class.
I want to add resources like Texture to a map like this:
typedef std::unordered_map<std::string, Resource*> ResourceMap;
And I want the name of the 'class + counter' to be the string/name of the Resource. Unfortunately everything just ends up being called P8Resource
because these classes derive from 'Resource'. An untimely predicament indeed, but typeid must know somehow that texture
is a Texture, not Resource.
class Resource {}; // abstract
class Texture : public Resource {};
Resource *texture = new Texture();
Texture *texture2 = new Texture();
typeid(texture).name(); // yields 'Resource'
typeid(texture2).name(); // yields 'Texture'
How can I make the first typeid
statement yield 'Texture' without using type conversions?
typeid
of a pointer will always be the declared type, because that's the real type of the pointer itself. To know the real type of the object the pointer points to, you need to dereference the pointer to get the actual type: http://ideone.com/FYmp79
#include <iostream>
#include <typeinfo>
using namespace std;
struct Resource {
virtual ~Resource() = default;
};
struct Texture : Resource {};
int main() {
Resource *resource = new Resource;
Resource *texture = new Texture;
cout << typeid(*resource).name() << endl; // yields 'Resource'
cout << typeid(*texture).name() << endl; // yields 'Texture'
return 0;
}
EDIT: as other people said, you need to make the class polymorphic to get the runtime type information.
My problem is that typeid(..).name() returns the wrong name of the class.
typeid(...).name()
is only useful for debugging or logging purposes. As http://en.cppreference.com/w/cpp/types/type_info/name says:
No guarantees are given, in particular, the returned string can be identical for several types and change between invocations of the same program.
As for your problem,
How can I make the first typeid statement yield 'Texture' without using type conversions?
The safest, easiest and most correct way to do this would be to add a virtual name function of your own to Resource
:
virtual std::string name() const = 0;
Then override it in every subclass to return the name of the class.
Firstly, typeid
can provide dynamic run-time type identification only for values of polymorphic class types. Your classes are not polymorphic. You need at least one virtual method in the base class in order to "activate" the dynamic behavior of typeid
.
Secondly, in order to use typeid
for determining the dynamic type of polymorphic object, you have to apply it to the object itself, not to a pointer to the object (as in your code).
Thirdly, the value returned by name()
does not mean much and cannot be used for any practical purposes. Formally, name()
can simply return an empty string every time. You have to use (and compare) the type_info
objects themselves for run-time type identification.
The typeid
operator can only return the dynamic type of an expression, if that expression is a glvalue to an object of a polymorphic class.
A class is polymorphic if it defines at least one virtual member function, directly or in one of its bases.
Since your Resource
class and the derived classes don't satisfy this requirement, the typeid
operator can only access the static type.
To solve that, and issues that you will run into as soon as you try to delete
a pointer to such a resource, make the destructor virtual.
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