- 此问题在此处已有答案**:
Inheritance in std::map with base class as value(4个答案)
3天前关闭。
我希望有一个函数能接受一个std::map
,它包含一个基类(指向一个基类的指针),但是我不能让它工作,下面是我的最小化和简化的例子:
struct Entity {
int i;
Entity(const int i_) : i(i_) {}
virtual ~Entity() {}
};
struct A : public Entity {
bool a;
A(const int i_, const bool a_) : Entity(i_), a(a_) {}
};
void efunc(const std::map<int, std::shared_ptr<Entity>>& m) {
for (auto& it : m) {
std::cout << it.second->i << std::endl;
}
}
int main() {
std::map<int, std::shared_ptr<A>> aMap;
std::shared_ptr<A> myA = std::make_shared<A>(1, true);
aMap.insert({myA->i, myA});
// efunc(aMap); // DOES NOT WORK
}
显然,简单地以这种方式传递map
是不允许的,但是我如何才能使它工作呢?
另外,如何在Map中检测类型,以便执行特定于该子类的代码?
先谢谢你!
- 更新:**使用模板似乎很有效,这就是我现在使用的模板:
template <class T>
void tfunc(const std::map<int, std::shared_ptr<T>>& m) {
for (auto& it : m) {
std::cout << it.second->i << std::endl;
}
}
这确实感觉有点奇怪,因为我失去了智能感知,我不明白为什么编译器没有给我一个错误。我觉得concept
s可能会有帮助(例如,确保T
继承Entity
),但这超出了我现在需要的。
再次感谢您的所有回应!
- 更新2:**好的,这里使用概念来确保
template
包含成员i
:
- 更新2:**好的,这里使用概念来确保
template <class T>
concept hasI = requires(T a) { a.i; };
template <class T>
concept inheritsEntity = std::derived_from<T, Entity>;
template <hasI T>
/// alternative: template<inheritsEntity T>
void tfunc(const std::map<int, std::shared_ptr<T>>& m) {
for (auto& it : m) {
std::cout << it.second->i << std::endl;
}
}
3条答案
按热度按时间9cbw7uwe1#
要回答第一个问题,可以使用 * 模板编程 *;编译器将为您生成特定于所需类型的代码:
然后可以在
main
函数中使用以下命令调用该函数:关于第二个问题(如何执行特定于您的类型的代码),可以在编译时使用以下命令进行检查:
gab6jxml2#
您可以将
aMap
设置为std::map<int, std::shared_ptr<Entity>>
,但仍然保留指向A
示例的共享指针。在下面的代码中,将存储在Map中的
myA
的类型为std::shared_ptr<Entity>
,但初始化时使用了指向类A
示例的共享指针。这是可以的,因为A
是从Entity
派生的。如下面所述,
myA
也可以是std::shared_ptr<A>
,并且仍然存储在aMap
中:或者,如果很少使用
efunc
,则可以将aMap
保留为std::map<int, std::shared_ptr<A>>
。然后,每当需要调用
efunc
时,创建一个包含aMap
内容副本的临时std::map<int, std::shared_ptr<Entity>>
,并使用它调用efunc
。共享指针仍将引用原始对象。
它的效率很低,但如果您不经常使用
efunc
,它可能就足够了。mklgxw1f3#
将std::map变量的声明从:
致:
这样,Map就与efunc函数所期望的相匹配。
使用继承,你确实可以在aMap数据结构中插入Entity类型的示例,以及从Entity派生类型的示例,struct A就是这种情况。
要检测map中的类型,可以使用一个作用域枚举作为Entity结构中的成员,也可以使用typeid运算符,该运算符返回std::type_info的示例,通过该示例可以获取类型的名称。
但是,不保证返回的名称在不同的实现中相同。
========从叮当声输出========
myint具有类型:我
mystr具有类型:NSt3__112基本字符串IcNS_11字符特性IcEENS_9分配器IcEEEE
======== MSVC的输出========
myint具有类型:整数
mystr具有类型:类标准::基本字符串〈字符,结构〉标准::字符特性,类标准::分配器〉
因此,您可能希望改用dynamic_cast,例如: