0

我有一个类层次结构,基类具有打印类名的功能:

#include <iostream>
using namespace std;

class base
{
public:
  virtual void print_name() { cout << typeid(*this).name() << endl; };
};

class derived1 : public base { };

class derived2 : public base { };

int main ()
{
  base Base;
  Base.print_name();

  derived1 Derived1;
  Derived1.print_name();

  derived2 Derived2;
  Derived2.print_name();
}

上面的输出是

class base
class derived1
class derived2

实际上,这取决于平台。

是否有一种或多或少的标准方法可以为每个类“附加”一些唯一名称,因此它可以用于printname()使所有平台的输出相同(并且独立于对真实类名所做的任何更改)?

4

3 回答 3

2

当然:

class base {
  public:
    virtual char const *name() const { return "base"; }
};

class derived1 : public base {
  public:
    virtual char const *name() const { return "derived1"; }
};

但是,如果您不在name一个类中覆盖,它的名称将是它的超类的名称。这可能是错误或功能,具体取决于您的用例。如果这是一个错误,那么您可以添加一些运行时检查以确保该方法被覆盖:

virtual char const *name() const {
    if (typeid(*this) != typeid(base))
        throw std::logic_error("name() not overridden");
    return "base";
}

但是您必须在name必须覆盖的每个实现中重复此检查。

于 2012-05-28T11:00:07.277 回答
1

您可以有效地使用type_info它。

type_info支持before符合弱顺序的方法,std::map只要提供用户提供的谓词,就可以在(例如)中使用它。

struct TypeInfoLess {
     bool operator()(std::type_info const* lhs, std::type_info const* rhs) const {
         return lhs->before(rhs);
     }
};

struct AdditionalTypeInfo {
    std::string name;
};

typedef std::map<std::type_info const*, AdditionalTypeInfo, TypeInfoLess> TypeInfoMap;

然后,您可以添加/搜索类型:

template <typename T>
void add(TypeInfoMap& map, T const& t, AdditionalTypeInfo const& ati) {
    map[&typeid(t)] = ati;
}

template <typename T>
AdditionalTypeInfo const* find(TypeInfoMap const& map, T const& t) {
    TypeInfoMap::const_iterator it = map.find(&typeid(t));
    if (it == map.end()) { return 0; }
    return &it->second;
}

int main() {
    TypeInfoMap timap;

    add(timap, timap, { "TypeInfoMap" });

    if (AdditionalTypeInfo const* const ati = find(timap, timap)) {
        std::cout << ati->name << "\n";
    }
}

注意:然后您有责任将您可能想要的每种类型添加到地图中。

于 2012-05-28T11:48:14.730 回答
0

您可以使用模板函数(或特征类)来获取名称:

template<typename T> const char * ClassName(T const * objPtr);

template<> const char * ClassName<derived1>(derived1 const *objPtr) { return "derived1"; }
template<> const char * ClassName<derived2>(derived2 const *objPtr) { return "derived2"; }

(这里的函数参数仅用于模板参数匹配)。在调用代码时,您可以将指针转换为特定类并使用 ClassName

derived1 * pDerived = static_cast<derived1*>(pPointer);
cout << ClassName(pDerived);

然而,这都是编译时的,您将需要一些机制(如 GUID)在运行时识别一个类(将其转换为正确的指针类型)。如果您的类没有并且您无法修改它们,那么我无法帮助您;(但是您可以使用特征技术来本地化与平台相关的类型选择代码。

于 2012-05-28T11:46:10.813 回答