std :: map无法处理多态?

时间:2009-05-07 07:07:29

标签: c++

在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时,多态性不起作用。

5 个答案:

答案 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