Domanda

I have a factory method class that generates "Items" and returns a pointer to the Item that it creates.

I have derived classes of Item. For example, Item can be a "weapon" "consumable" or "armor."

I need to detect which type of Item is created so that I can properly cast the Item to that type. I did some test lines and it looks like it's doing what I want, except for adding a number associated with the type.

Example:

I had the line:

cout << "Type Created: " << typeid(pItem).name() << endl;

Which return the base class Item, but it would display: "4Item"

I then changed that to:

cout << "Type Created: " << typeid(*pItem).name() << endl;

Which would give me the correct derived type, but also throw in that number. So I get something like "5Armor"

Why did pItem return the base class? And why does it return an int with the type? How can I remove the int?

A solution that does what I want - In a "cheating" kind of way:

            string type;
            string returnedType = typeid(*pItem1).name();
            for (int i=1; i < returnedType.length(); i++){
                    type.push_back(returnedType[i]);
            }
            cout << "type: " << type << endl;

Thanks

È stato utile?

Soluzione 3

You probably shouldn't use type-codes and switch/downcasts for this. Instead, put your object-specific code into a virtual method or (depending on the problem at hand) use a visitor pattern. Your current approach will probably look something like this in the end:

int price = 0;

if (obj->get_type_str() == "armor")
{
    price = 1000 + ((Armor *)obj)->get_durability() * 100;
}
else if (obj->get_type_str() == "ninjasword")
{
    price = 5000 * ((NinjaSword *)obj)->get_damage();
}
else if (obj->get_type_str() == "bfg")
{
    price = 20000;
}

shop->show_price(price);

The problem is, that this isn't very extensible. Instead of defining the price of an object along with the object, it will be littered around the code. A better way would be to provide a virtual method get_price(), that can do this:

class GameObject
{
public:
    virtual ~GameObject() {}
    virtual int get_price() const = 0;
};

class Armor: public GameObject
{
public:
    virtual int get_price() const
    {
        return 1000 + durability * 100;
    }

private:
    int durability;
};

class NinjaSword: public GameObject
{
public:
    virtual int get_price() const
    {
        return 5000 * damage;
    }

private:
    int damage;
};

class Bfg: public GameObject
{
public:
    virtual int get_price() const
    {
        return 20000;
    }
};

Now your object-specific code stays in the object and the previous code example simply becomes:

shop->show_price(obj->get_price());

If the code in question doesn't really belong to the object, this may be a case for the Visitor pattern.

Altri suggerimenti

typeid returns a const std::type_info&. The std::type_info type has a function called name that returns an implementation-defined string representation of the name of the underlying type. There are absolutely no guarantees about what this function is going to return - it doesn't have to return a string that looks anything at all like the name of the type in the original program, and can decorate it however it would like to.

If you need to keep track of the name of the type that you created, I would suggest just adding in a virtual function like this one to your hierarchy:

virtual std::string getType() const = 0;

This function could return a nice, human-readable representation of the type that is guaranteed to behave in the way that you want (because you're responsible for writing it).

Hope this helps!

I use g++ and also had this problem. Now strictly answering your question without any intention to point what's the best approach, there is another way to deal with this case.

Here is a copy/paste example for you:

Create a type of yours, like MyType.h

#ifndef __MYTYPE_H__
#define __MYTYPE_H__
class MyType {
};
#endif

and a main.cpp file, like this:

#include <cxxabi.h>
#include <iostream>
#include <typeinfo>

#include "MyType.h"

template <typename T> char* get_typename(T& object)
{
    return abi::__cxa_demangle(typeid(object).name(), 0, 0, 0);
}

int main(int argc, char ** argv)
{
    MyType my_type;

    std::cout << get_typename(my_type) << std::endl;

    return 0;
}

This would output: MyType

I came to this solution based on an answer from this post that took me to this article.

If you just need to convert pointers, you don't have to create your own type identifier. Just use dynamic_cast to convert the pointer. If the type doesn't match you'll get a null pointer, and you can try another type. Or you can compare the typeid of the pointer and the typeid of each target type directly.

Of course, not having to do this kind of runtime type searching is even better.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top