2017-01-28 2 views
3

Ich habe eine Basis std::vector und eine std::initializer_list<Attribute*>, die Argument zur Funktion bestehend aus abgeleiteten Klassen von Attribute Klasse ist.Vorhandene Typen sollten ersetzt werden, neue Typen hinzugefügt werden

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); 

Was updateBaseList tun muß, ist, wenn der Typ eines Elements der l einen in baseList gleich ist, mit dem von l in baseList diesen Wert aktualisieren. Wenn der Typ in baseList nicht gefunden wird, muss er hinzugefügt werden.

Beachten Sie, dass der gesuchte Typ nicht Attribute* ist, sondern die abgeleiteten Klassen.

Mein Versuch

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); 
     } 
    } 
} 

Aber die typeid(**listIt) und typeid(**attrIt) immer Base zurückzukehren.

Ziel

Wenn ich rufe updateBaseList(baseList, { time2, place2 }) baseList { place2, time2, way }

Antwort

2

Sie die Klassenhierarchie polymorphen vornehmen müssen sein sollte. Ein guter Weg, dies zu tun, ist durch eine virtual ~Attribute() { } destructor Zugabe:

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

Ihr Code dann 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); 
} 

Unrelated, aber Sie können Ihre Implementierung von baseList erleichtern C lesen mit ++ 11 Bereich für Schleifen:

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); 
     } 
    } 
} 

Sie können Nutzen Sie auch Standardalgorithmen, um die stateful Variable zu vermeiden:

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; 
     } 
    } 
} 
Verwandte Themen