我不是在谈论typeid,我只是在寻找将单个对象(例如我的情况下的std :: string)绑定到某个类的对象并使其getter多态的东西的通用方法。我不能真正给出一个正确的定义,所以我认为这就像获得一个类名的问题,但你自己设置在某个地方,唯一的问题是你在哪里设置它,你如何返回它。
我只是举几个例子来做我想做的事,但并不像我想要的那样高效。
virtual string GetClassName() const { return string("MyClass"); }
- 每次调用时都会花费额外的时间来构建和复制字符串const string& GetClassName() const { return class_name_; }
其中class_name_
是在构造函数中设置的受保护类字段 - 相同的字符串存储在每个对象中,因此它不具有内存效率我正在考虑将const引用返回给静态对象,但我无法真正找到使其具有多态性的方法。
有任何想法吗?
当你可以用正确的轮胎延长它时,你不需要重新发明轮子。
C ++标准为您提供适用于所有情况的typeid()
,包括内置类型,自定义类,多态类,多重继承,虚拟继承等等。
现在你可能不喜欢typeid()
使用的名称,这些名称是特定于实现的。或者,您可能希望使用自己的类型管理扩展来扩展可用信息。在这种情况下,Bjarne Stroustrup在“C ++的设计和演化”中提出了一个非常简单有效的解决方案。
typeid()
返回对const std::type_info
的引用。现在,您可以在unordered_map
中使用此对象的地址,将类型映射到您自己的可提供所需名称的自定义信息。
此解决方案的优点:使用强大的内置功能,基于每个类的一个额外对象(可能是静态的),获得名称的开销非常低。您需要做的就是考虑如何最好地填充地图。
这里有一个小而快速的概念证明(当然必须改进):
// Basic principle of the idea
map<const type_info*, string> mytypes;
template <class T>
const string& mytype(T &&x) {
return mytypes[&typeid(x)];
}
// Some test types
struct A { virtual int test() {} };
struct B : A {};
int main() {
// To be improved: initialization of the type info extension
mytypes[&typeid(int)]="Plain C++ integer";
mytypes[&typeid(A)]="Structure A";
mytypes[&typeid(B)]="Structure B";
// demo, including polymorphic type
int a;
A * p = new B;
cout << typeid(int).name() <<endl;
cout << mytype(a) <<endl;
cout << mytype(*p) <<endl;
return 0;
}
我认为你想要的是一些带有NamedClass
的基础virtual std::string_view getName() const
,它返回派生类的名称。所以你想要像typeid(object).name()
这样的东西,但没有名字错误。
从NamedClass
派生的每个类都应该覆盖getName
并返回类名。
class NamedClass {
public:
virtual std::string_view getName() const = 0;
};
class Derived final : public NamedClass {
public:
std::string_view getName() const override {
return "Derived";
}
};
如果你像我一样讨厌这种重复,你可以使用一个宏。
#define GET_NAME(NAME) \
std::string_view getName() const override { return #NAME; }
class Derived final : public NamedClass {
public:
GET_NAME(Derived)
};
我强烈建议使用std::string_view
而不是const std::string &
,如果你想做的就是“查看”字符串。