8

我有一个工厂方法类,它生成“项目”并返回一个指向它创建的项目的指针。

我有 Item 的派生类。例如,Item 可以是“武器”、“消耗品”或“盔甲”。

我需要检测创建了哪种类型的项目,以便我可以正确地将项目转换为该类型。我做了一些测试行,看起来它正在做我想做的事,除了添加一个与类型相关的数字。

例子:

我有这行:

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

它返回基类 Item,但它会显示:“4Item”

然后我将其更改为:

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

这会给我正确的派生类型,但也会输入那个数字。所以我得到类似“5Armor”的东西

为什么 pItem 返回基类?为什么它会返回一个 int 类型?我怎样才能删除int?

一个做我想要的解决方案 - 以一种“作弊”的方式:

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

谢谢

4

4 回答 4

9

typeid返回一个const std::type_info&。该std::type_info类型有一个调用函数,该函数name返回底层类型名称的实现定义的字符串表示形式。绝对不能保证这个函数将返回什么 - 它不必返回一个看起来像原始程序中类型名称的字符串,并且可以随心所欲地装饰它。

如果您需要跟踪您创建的类型的名称,我建议您在层次结构中添加一个像这样的虚函数:

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

这个函数可以返回一个很好的、人类可读的类型表示,它保证按照你想要的方式运行(因为你负责编写它)。

希望这可以帮助!

于 2013-05-04T23:53:21.810 回答
8

我使用 g++ 也遇到了这个问题。现在严格回答您的问题,无意指出最佳方法是什么,还有另一种处理这种情况的方法。

这是给您的复制/粘贴示例:

创建您的类型,例如 MyType.h

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

和一个 main.cpp 文件,如下所示:

#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;
}

这将输出: MyType

我是根据这篇文章的回答得出这个解决方案的,该回答把我带到了这篇文章

于 2014-04-27T04:20:30.970 回答
4

您可能不应该为此使用类型代码和开关/向下转换。相反,将您的特定于对象的代码放入虚拟方法或(取决于手头的问题)使用访问者模式。您当前的方法最终可能看起来像这样:

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);

问题是,这不是很可扩展。它不会随对象一起定义对象的价格,而是散布在代码周围。更好的方法是提供一个虚拟方法 get_price(),它可以做到这一点:

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;
    }
};

现在您的对象特定代码保留在对象中,前面的代码示例简单地变为:

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

如果有问题的代码并不真正属于该对象,这可能是访问者模式的一种情况。

于 2013-05-05T00:27:37.333 回答
1

如果您只需要转换指针,则不必创建自己的类型标识符。只是dynamic_cast用来转换指针。如果类型不匹配,您将获得一个空指针,您可以尝试其他类型。或者您可以直接比较typeid指针的和typeid每个目标类型的。

当然,不必进行这种运行时类型搜索会更好。

于 2013-05-05T00:28:28.953 回答