在c ++中使用std :: map时,是否可以将继承的类作为其“基类”存储在地图中,并且仍然可以调用它们的重载方法?见这个例子:
#include <iostream>
#include <map>
class Base
{
public:
virtual void Foo() { std::cout << "1"; }
};
class Child : public Base
{
public:
void Foo() { std::cout << "2"; }
};
int main (int argc, char * const argv[])
{
std::map<std:string, Base> Storage;
Storage["rawr"]=Child();
Storage["rawr"].Foo();
return 0;
}
以下代码写入“1”。以某种方式告诉我,当你使用std :: map时,多态性不起作用。
答案 0 :(得分:15)
多态性在这种情况下不起作用,因为std :: map将Base存储为值类型,因此objects get sliced。
如果要在存储对象上使用多态,则需要存储指针或使用boost ptr containers之一来实现相同的效果。这意味着您需要记住之后删除内存(请不要将指向堆栈对象的指针放入地图中)
答案 1 :(得分:3)
Object Slicing的情况。尝试插入指针。
在存在继承的情况下,复制会导致切片。也就是说,如果您创建基类对象的映射并尝试将派生类对象插入其中,则在将对象(通过基类复制构造函数)复制到映射中时,将删除对象的派生性。
因此,建议使用指针而不是复制本身。
答案 2 :(得分:1)
第一个想法是,要获得多态性,您需要在指针或引用上调用成员方法。我会在地图中存储指向基类的指针(你存储的元素被复制),然后像这样通过指针调用:
#include <iostream>
#include <map>
class Base
{
public:
virtual void Foo() { std::cout << "1"; }
};
class Child : public Base
{
public:
void Foo() { std::cout << "2"; }
};
int main (int argc, char * const argv[])
{
std::map<std::string, Base*> Storage;
Storage["rawr"] = new Child();
Storage["rawr"]->Foo();
return 0;
}
你得到结果“2”。
注意:您现在必须处理已分配的内存。
答案 3 :(得分:1)
动态多态只适用于引用和指针。如果使用容器,它会复制对象内部的对象 - 只能使用指针。
如果您在不使用指针或引用的情况下强制从超类型转换为基类型,则对象内存将切片。看看这个:Object slicing wikipedia article
答案 4 :(得分:0)
不,您必须将指针存储到基类以获取多态行为。您现在的方式将导致slicing。