2012-04-15 3 views
1

У меня есть класс шаблонов для группы объектов, из которых могут быть получены другие более специализированные группы (используя это для композитного рисунка). Во всяком случае, мой класс Group обрабатывает весь фактический код группы.Динамический литой или второй контейнер объектов?

Прямо сейчас у меня есть один контейнер, содержащий объекты типа T, но мне также нужно получить доступ к интерфейсу другого базового класса путем кросс-кастинга. Вы порекомендовали мне иметь контейнер для обоих интерфейсов или просто dynamic_cast каждый объект, когда я прохожу через первый контейнер?

class Sim_object { 
    add(Sim_object_sp_t object) 
    remove(Sim_object_sp_t object) 
}; 

class Group<T> : public class Sim_object { 
    add(Sim_object_sp_t object) 
    remove(Sim_object_sp_t object) 
    map<T> 
    protected iterators begin(), end() (for use by Ship_group to use for dock, attack, move functions) 
    // looking to add map<Sim_object> to prevent casting from T to Sim_object in Add/Remove but still give derived classes access to map<T> iterators. 
}; 

class IShip { 
    dock() = 0 
    attack() = 0 
    move() = 0 
}; 

class Ship_group : public Group<IShip>, public IShip { 
    dock() // uses iterators provided by Group to loop through and call dock() 
    attack() // same as dock 
    move() // same as dock 
}; 

class Ship : public Sim_object, public IShip { 
    dock() 
    attack() 
    move() 
}; 

Таким образом, для двух интерфейсов, к которым мне нужен доступ, в группе относятся T (IShip в этом случае) и Sim_object.

Пример из группы:

template<typename T> 
void Group<T>::add(Sim_object_sp_t object) { 
    if (object->get_parent()) 
    object->get_parent()->remove(object); 

    std::tr1::shared_ptr<T> t_object = std::tr1::dynamic_pointer_cast<T>(object); 
    if (!t_object) 
    throw Error("Failed to cast to type T"); 

    objects[object->get_name()] = t_object; 
    object->set_parent(shared_from_this()); 
} 

Пример из Ship_group:

void Ship_group::set_destination_position_and_speed(Point destination_position, double speed) { 
    for (Iterator it = begin(); it != end(); ++it) { 
    try { 
     it->second->set_destination_position_and_speed(destination_position, speed); 
    } catch (const Error& e) { 
     cout << it->second->get_name() << " -- " << e.msg << endl; 
    } 
    } 
} 
+0

Все ли функции класса 'Group' требуют, чтобы' T' имел желаемый интерфейс? Если это так, я думаю, вы можете просто запрограммировать свой шаблон 'Group', предполагая, что все' T' имеют желаемый интерфейс (не требуется 'dynamic_cast'). Компилятор шаблонов просто терпит неудачу при создании экземпляра класса 'Group' для любых типов' T', которые не соответствуют критериям. –

+0

Я не уверен, что это правильный ответ, но сейчас я получаю класс Ship_group из группы , где IShip является абстрактным базовым классом для всех судовых объектов. Поэтому я действительно не хочу загрязнять T. У меня также есть класс Sim_object, который Group наследует и выполняет функции компонента как часть составного шаблона. Я не хочу загрязнять любой интерфейс, чтобы я мог избежать dynamic_cast. Отвечает ли это на ваш вопрос? – keelerjr12

+0

Было бы полезно, если бы вы могли набросать скелетный код иерархии классов, который вы только что описали. Можете ли вы добавить это к своему вопросу? –

ответ

0

Возможно, вложенный тип внутри class Group<T>:

class Group<T> : public class Sim_object { 
    class Specialized_Sim_Object : public T, public Sim_object {} 
    void add(Specialized_Sim_Object * object) { 
     objects[object->get_name()] = object; 
    } 
} 

shared_ptr не может быть необходимым в данном случае, либо - когда Ship_group выполняет итерацию через e map, тип уже гарантированно будет IShip.

Смежные вопросы