【发布时间】:2017-06-06 14:36:06
【问题描述】:
假设您有一个包含 Item 类型的 std::vector 类,并且您存储继承的项目类型:武器、药水、盔甲等。您如何将项目检索为继承类而不是基类?
【问题讨论】:
-
您需要一个指针/引用向量以避免切片。然后您需要某种方法来检测对象的类型,RTTI 或类型标志。但多态性的全部意义在于您不需要知道确切的类型。
标签: c++
假设您有一个包含 Item 类型的 std::vector 类,并且您存储继承的项目类型:武器、药水、盔甲等。您如何将项目检索为继承类而不是基类?
【问题讨论】:
标签: c++
如何将项目检索为继承类而不是基类?
这说明你需要闭集多态,由std::variant或boost::variant提供。
using Entity = std::variant<Weapon, Potion, Armor>;
// An `Entity` is either a `Weapon`, a `Potion`, or an `Armor`.
std::vector<Entity> entities;
struct EntityVisitor
{
void operator()(Weapon&);
void operator()(Potion&);
void operator()(Armor&);
};
for(auto& e : entities)
{
std::visit(EntityVisitor{}, e);
// Call the correct overload depending on what `e` is.
}
【讨论】:
visit 为您处理。如果e 是武器,那么EntityVisitor::operator()(Weapon&) 将被调用。
variant 和 visit 是否获得批准?我不知道他们把它变成了标准。值得注意的是en.cppreference.com 也不...
你的设计有一股难闻的味道。存储item* 的代价是不得不在vector 之外管理它们。 vector<item*> 的唯一良好动机是使用 items polymorphically。通过尝试检测您所证明的类型,您没有以多态方式使用它们。
更好的解决方案是将这些项目存储在单独的向量中,而不是公共的vector<item*> items,所以vector<weapon> weapons、vector<potion> potions、vector<armor> armors。
所以请不要使用这个代码,但是给定vector<item*> items你可以这样做:
for(auto i : items) {
if(dynamic_cast<weapon*>(i) != nullptr) {
auto iWeapon = static_cast<weapon*>(i);
// work with weapon here
} else if(dynamic_cast<potion*>(i) != nullptr) {
auto iPotion = static_cast<potion*>(i);
// work with potion here
} else {
assert(dynamic_cast<armor*>(i) != nullptr);
auto iArmor = static_cast<armor*>(i);
// work with armor here
}
}
【讨论】:
dynamic_casts 时,提示应该使用模板化。