typeinfo如何在多态的collection中得到class的name/id?
Typeinfo how to get the name/id of the class in a polymorphic collection?
在下面的示例中,我希望不是标准输出:Base Foo Bar
,但我得到 P4Base P4Base P4Base
:
#include <iostream>
#include <typeinfo>
#include <vector>
#include <memory>
class Base {};
class Foo : public Base {};
class Bar : public Base {};
using Collection = std::vector<std::unique_ptr<Base> >;
int main() {
Collection collection;
collection.push_back(std::make_unique<Base>());
collection.push_back(std::make_unique<Foo>());
collection.push_back(std::make_unique<Bar>());
for (auto &u:collection)
std::cout << typeid(u.get()).name() << std::endl;
}
有没有办法正确识别我的 collection 中的实例类型?
编辑
建议后的工作示例
struct Base {virtual ~Base() = default;};
struct Foo : public Base {};
struct Bar : public Base {};
using Collection = std::vector<std::unique_ptr<Base> >;
int main() {
Collection collection;
collection.push_back(std::make_unique<Base>());
collection.push_back(std::make_unique<Foo>());
collection.push_back(std::make_unique<Bar>());
for (auto &u:collection)
std::cout << typeid(*u).name() << std::endl;
}
变量 var
的表达式 typeid(var).name()
在不同类型中应该是唯一的。但是,对于索引和一般区分用途,您应该使用 typeid(var).hash_code()
.
您看到的输出是由于 u
变量被 auto
推断为 总是 是 std::unique_ptr<Base>
类型.
解决此问题的一种方法是将 virtual
成员添加到您的 class 中,即 return 各自 this
指针的 typeid
。然后,在 u
指针上对该函数的每次调用都将调用 actual 派生的 class override:
class Base {
public:
virtual const char* name() { return typeid(this).name(); }
};
class Foo : public Base {
public:
const char* name() override { return typeid(this).name(); }
};
class Bar : public Base {
public:
const char* name() override { return typeid(this).name(); }
};
using Collection = std::vector<std::unique_ptr<Base> >;
int main()
{
Collection collection;
collection.push_back(std::make_unique<Base>());
collection.push_back(std::make_unique<Foo>());
collection.push_back(std::make_unique<Bar>());
for (auto& u : collection)
std::cout << u->name() << std::endl;
return 0;
}
Typeinfo how to get the name/id of the class in a polymorphic collection?
- 首先,classes 必须是多态的,以便
typeid
提供动态类型。你的 classes 不是多态的,所以你会得到静态类型。
- 其次,必须使用指向对象的左值而不是指针。将
typeid
应用于指针会为您提供指针类型的类型信息,而不是指向对象的类型。
- 第三,你的程序的行为是未定义的,因为派生对象是通过非虚拟析构函数指向基的指针销毁的。
要修复第一点和第三点,请为基类提供一个虚拟析构函数。修复第二个:
typeid(*u).name()
最后,您对可读 class 名称的期望是错误的。 std::type_info::name
不能保证为您提供您为 class 编写的名称。结果是实现定义的,在实践中,您通常会得到类型的错位名称。没有获得可读名称的标准方法,但有实现定义的方法来分解名称。
有几个问题。
u.get()
具有“指向 Base 的指针”类型。如果要打印对象本身的类型,请尝试 typeid(*u.get()).name()
.
- 如果您想要多态行为,请使用多态 类。这需要在
Base
中至少定义一个虚函数。无论如何,您需要定义一个虚拟析构函数才能正确删除对象。没有一个,程序有UB。
name()
returns 一个实现定义的字符串,所以你不能指望 Base Foo Bar
。如果您解决其他问题,您可能会得到类似的东西。 Live demo.
在下面的示例中,我希望不是标准输出:Base Foo Bar
,但我得到 P4Base P4Base P4Base
:
#include <iostream>
#include <typeinfo>
#include <vector>
#include <memory>
class Base {};
class Foo : public Base {};
class Bar : public Base {};
using Collection = std::vector<std::unique_ptr<Base> >;
int main() {
Collection collection;
collection.push_back(std::make_unique<Base>());
collection.push_back(std::make_unique<Foo>());
collection.push_back(std::make_unique<Bar>());
for (auto &u:collection)
std::cout << typeid(u.get()).name() << std::endl;
}
有没有办法正确识别我的 collection 中的实例类型?
编辑
建议后的工作示例struct Base {virtual ~Base() = default;};
struct Foo : public Base {};
struct Bar : public Base {};
using Collection = std::vector<std::unique_ptr<Base> >;
int main() {
Collection collection;
collection.push_back(std::make_unique<Base>());
collection.push_back(std::make_unique<Foo>());
collection.push_back(std::make_unique<Bar>());
for (auto &u:collection)
std::cout << typeid(*u).name() << std::endl;
}
变量 var
的表达式 typeid(var).name()
在不同类型中应该是唯一的。但是,对于索引和一般区分用途,您应该使用 typeid(var).hash_code()
.
您看到的输出是由于 u
变量被 auto
推断为 总是 是 std::unique_ptr<Base>
类型.
解决此问题的一种方法是将 virtual
成员添加到您的 class 中,即 return 各自 this
指针的 typeid
。然后,在 u
指针上对该函数的每次调用都将调用 actual 派生的 class override:
class Base {
public:
virtual const char* name() { return typeid(this).name(); }
};
class Foo : public Base {
public:
const char* name() override { return typeid(this).name(); }
};
class Bar : public Base {
public:
const char* name() override { return typeid(this).name(); }
};
using Collection = std::vector<std::unique_ptr<Base> >;
int main()
{
Collection collection;
collection.push_back(std::make_unique<Base>());
collection.push_back(std::make_unique<Foo>());
collection.push_back(std::make_unique<Bar>());
for (auto& u : collection)
std::cout << u->name() << std::endl;
return 0;
}
Typeinfo how to get the name/id of the class in a polymorphic collection?
- 首先,classes 必须是多态的,以便
typeid
提供动态类型。你的 classes 不是多态的,所以你会得到静态类型。 - 其次,必须使用指向对象的左值而不是指针。将
typeid
应用于指针会为您提供指针类型的类型信息,而不是指向对象的类型。 - 第三,你的程序的行为是未定义的,因为派生对象是通过非虚拟析构函数指向基的指针销毁的。
要修复第一点和第三点,请为基类提供一个虚拟析构函数。修复第二个:
typeid(*u).name()
最后,您对可读 class 名称的期望是错误的。 std::type_info::name
不能保证为您提供您为 class 编写的名称。结果是实现定义的,在实践中,您通常会得到类型的错位名称。没有获得可读名称的标准方法,但有实现定义的方法来分解名称。
有几个问题。
u.get()
具有“指向 Base 的指针”类型。如果要打印对象本身的类型,请尝试typeid(*u.get()).name()
.- 如果您想要多态行为,请使用多态 类。这需要在
Base
中至少定义一个虚函数。无论如何,您需要定义一个虚拟析构函数才能正确删除对象。没有一个,程序有UB。 name()
returns 一个实现定义的字符串,所以你不能指望Base Foo Bar
。如果您解决其他问题,您可能会得到类似的东西。 Live demo.