应替换现有类型,添加新类型

时间:2017-01-28 12:15:53

标签: c++

我有一个基数std::vector和一个std::initializer_list<Attribute*>,它是函数的参数,由Attribute类的派生类组成。

class Attribute {};
class Place : public Attribute {};
class Time : public Attribute {};
class Way: public Attribute {};

Place* place = new Place();
Time* time = new Time();
Way* way = new Way();
Place* place2 = new Place(...);
Time* time2 = new Time(...);

auto baseList = std::vector<Attribute*>({ place, time, way })

void updateBaseList(std::vector<Attribute*>& v, std::initializer_list<Attribute*> l);

updateBaseList必须做的是,如果l中元素的类型等于baseList中的元素的类型,则使用baseList中的值更新l中的值{1}}。如果baseList中未遇到该类型,则必须添加该类型。

请注意,搜索的类型不是Attribute*,而是派生类。

我的尝试

void updateBaseList(std::vector<Attribute*>& v, std::initializer_list<Attribute*> l) {
    bool found;
    for (auto listIt = l.begin(); listIt != l.end(); ++listIt) {
        found = false;
        for (auto attrIt = baseList.begin(); attrIt != baseList.end(); ++attrIt) {
            if (typeid(**listIt) == typeid(**attrIt)) {
                *attrIt = *listIt;
                found = true;
                break;
            }
        }
        if (!found) {
            baseList.push_back(*listIt);
        }
    }
}

typeid(**listIt)typeid(**attrIt)始终返回Base

目标

如果我调用updateBaseList(baseList, { time2, place2 }) baseList应为{ place2, time2, way }

1 个答案:

答案 0 :(得分:3)

您需要使类层次结构具有多态性。这样做的一个好方法是添加virtual ~Attribute() { }析构函数:

struct Attribute 
{
    virtual ~Attribute() { }
};

您的代码然后works as expected

{
    auto baseList = std::vector<Attribute*>({ place0, time0 });

    updateBaseList(baseList, {place2, time2, way0});
    assert(baseList[0] == place2);
    assert(baseList[1] == time2);
    assert(baseList[2] == way0);
    assert(baseList.size() == 3);

    updateBaseList(baseList, {place0});
    assert(baseList[0] == place0);
    assert(baseList[1] == time2);
    assert(baseList[2] == way0);
    assert(baseList.size() == 3);
}

不相关,但您可以使用C ++ 11 range-for循环更容易阅读baseList的实现:

void updateBaseList(std::vector<Attribute*>& v, std::initializer_list<Attribute*> l) 
{
    for (auto& litem : l) 
    {
        bool found = false;
        for (auto& attr : baseList) 
        {
            if (typeid(*litem) != typeid(*attr)) continue;

            attr = litem;
            found = true;
            break;
        }

        if (!found) 
        {
            v.push_back(litem);
        }
    }
}

您还可以利用标准算法来避免有状态found变量:

void updateBaseList(std::vector<Attribute*>& v, std::initializer_list<Attribute*> l) 
{
    for (auto& litem : l) 
    {
        const auto found = std::find_if(std::begin(v), std::end(v), [&](Attribute* p)
                                       {
                                           return typeid(*litem) == typeid(*p);
                                       });

        if (found == std::end(v)) 
        {
            v.push_back(litem);
        }
        else 
        {
            *found = litem;
        }
    }
}