2012-04-03 4 views
2

У меня есть карта контейнер для хранения определенных объектов, вместе со своим именем и типом:Получение поля из STL карты итератора

typedef std::map<std::string, std::pair<ObjType, ObjBase*> > ObjContainer; 

Однако во многих частях коды, есть конструкции, как это:

ObjContainer::iterator it = mObjContainer.find(name); 
if (it != mObjContainer.end()) { 
    if (it->second.second) { 
     it->second.second->setObj2Default(); 
     delete it->second.second; 
     it->second.second = 0; 
    } 
} 

Очевидно, что многие "it-> second.second" не очень ясны, и неосновательный. Если он изменен в будущем, для поддержки еще одного поля, например, все будет разбито. Итак, я пытаюсь изменить их функции, чтобы получить доступ к полям, как это:

ObjBase*& getObjPtr(ObjContainer::iterator it) { 
    return it->second.second; 
} 

Аналогично, также функционируют getObjName и getObjType.

Было также предложено мне, что было бы более понятно, чтобы итератор возвращающегося эти поля:

it.objPtr(); 
it.objName(); 
it.objType(); 

Но я думаю, что STL итераторы не должны быть унаследованы, чтобы эти функции, не так ли? Я не вижу другого способа сделать это, кроме как создать оболочку для карты и иметь свой собственный итератор с этими функциями.

Итак, что было бы наиболее подходящим вариантом? Есть ли другой способ решить эту проблему, которую я не вижу?

+2

Почему вы не просто использовать на структуру вместо пары и назовите свои поля так, как вы хотите? – Spidey

+0

@Spidey: зачем откатывать собственные определения классов, если библиотека уже поставляется с совершенно исправным? –

+0

Вы можете обернуть аттракторами.По крайней мере, вам удастся избежать использования пары. Первый, пара.секунд, пара-> второй-> второй и т. Д. – Spidey

ответ

2

Я бы просто сделать локальную копию указателя (или ссылки) - это, вероятно, будет оптимизирован в любом случае:

ObjContainer::iterator const it = mObjContainer.find(name); 
if (it != mObjContainer.end()) 
{ 
    ObjBase * & p = it->second.second; 
    if (p) { p->foo(); delete p; p = NULL; } 
} 
0

Используйте ссылку для упрощения синтаксиса.

ObjContainer::iterator it = mObjContainer.find(name); 
if (it != mObjContainer.end()) { 
    std::pair<ObjType, ObjBase*> & ref = it->second; 
    if (ref.second) { // ... 
4

Если самая большая проблема является ремонтопригодностью, я бы заменить зЬй :: пару с пользовательским классом/структурой, которая оборачивает ObjType и ObjBase * как единое целое.

  • легко добавить новое поле в соединении
  • легко получить доступ STRUCT поля ObjType и ObjPair
  • легко писать геттеры/сеттеры/другие функции для класса, которые обрабатывают ObjType и ObjPair
0

Я сначала задался вопросом о том, является ли ObjType обязательным. Если целью является просто указать, какой класс на самом деле указывает второй параметр ObjBase * пары, используйте dynamic_cast и избавьтесь от пары. не

typedef std::map<std::string, ObjBase*> ObjContainer; 

Нет больше second.second в коде, то:

ObjContainer::iterator it = mObjContainer.find(name); 
if (it != mObjContainer.end()) { 
    if (it->second) { 
     it->second->setObj2Default(); 
     delete it->second; 
     it->second = NULL; 
    } 
} 

И когда вам нужно проверить фактический тип объекта:

ObjContainer::iterator it = mObjContainer.find(name); 
if (it != mObjContainer.end()) { 
    if (ChildObj* p_Child = dynamic_cast<ChildObj*>(it->second)) { 
     // Work on p_Child... 
    } 
} 
+0

Нет, ObjType необходим, потому что иногда ObjBase * будет пустым, а ObbType может быть используется для создания нового экземпляра с использованием фабрики. –