Самый простой способ - иметь перечисление типа комнаты, как предлагает вам @billz. Проблема с этим способом заключается в том, что вы не должны забывать добавлять значение в перечисление и использовать его один раз каждый раз, когда вы добавляете новый тип комнаты в систему. Вы должны быть уверены, что используете значения перечисления только один раз, один раз для каждого класса.
Но, с другой стороны, проекты, основанные на наследовании, имеют смысл только в том случае, если типы иерархии имеют общее поведение. Другими словами, вы хотите использовать их одинаково, независимо от их типа. ИМПО, дизайн OO/наследования — не лучший способ сделать это.
Причудливый и масштабируемый способ, которым я делаю такие вещи, — это списки типов.
Обычно у вас есть разные критерии поиска для каждого типа в вашей системе. И во многих случаях результаты этого поиска неодинаковы для разных типов вашей системы (разве не одно и то же для поиска комнаты класса люкс и для поиска обычной комнаты, у вас могут быть разные критерии поиска и/или может потребоваться другой поиск). данные результатов).
Для этого в системе есть три списка типов: один, содержащий типы данных, один, содержащий типы критериев поиска, и один, содержащий типы результатов поиска:
using system_data_types = type_list<NormalRoom,LuxuryRoom>;
using search_criteria_types = type_list<NormalRoomsCriteria,LuxuryRoommsCriteria>;
using search_results_types = type_list<NormalRoomSearchResults,LuxuryRoomSearchResults>;
Обратите внимание, что списки типов сортируются таким же образом. Это важно, как показано ниже.
Итак, реализация поисковой системы:
class SearchEngine
{
private:
std::vector<VectorWrapper*> _data_lists; //A vector containing each system data type in its own vector. (One vector for NormalRoom, one for LuxuryRoom, etc)
//This function returns the vector that stores the system data type passed.
template<typename T>
std::vector<T>& _get_vector() {...} //Implementation explained below.
public:
SearchEngine() {...}//Explanation below.
~SearchEngine() {...}//Explanation below.
//This function adds an instance of a system data type to the "database".
template<typename T>
void addData(const T& data) { _get_vector<T>().push_back( data ); }
//The magic starts here:
template<typename SEARCH_CRITERIA_TYPE>//This template parameter is deduced by the compiler through the function parameter, so you can ommit it.
typename search_results_types::type_at<search_criteria_types::index_of<SEARCH_CRITERIA_TYPE>> //Return value (The search result that corresponds to the passed criteria. THIS IS THE REASON BECAUSE THE TYPELISTS MUST BE SORTED IN THE SAME ORDER.
search( const SEARCH_CRITERIA_TYPE& criteria)
{
using system_data_type = system_data_types::type_at<search_criteria_types::index_of<SEARCH_CRITERIA_TYPE>>; //The type of the data to be searched.
std::vector<system_data_type>& data = _get_vector<system_data_type>(); //A reference to the vector where that type of data is stored.
//blah, blah, blah (Search along the vector using the criteria parameter....)
}
};
А поисковик можно использовать следующим образом:
int main()
{
SearchEngine engine;
engine.addData(LuxuryRoom());
engine.addData(NormalRoom());
auto luxury_search_results = engine.search(LuxuryRoomCriteria()); //Search LuxuryRooms with the specific criteria and returns a LuxuryRoomSearchResults instance with the results of the search.
auto normal_search_results = engine.search(NormalRoomCriteria()); //Search NormalRooms with the specific criteria and returns a NormalRoomSearchResults instance with the results of the search.
}
Движок основан на хранении одного вектора для каждого типа системных данных. И движок использует вектор, который хранит эти векторы. У нас не может быть полиморфной ссылки/указателя на векторы разных типов, поэтому мы используем оболочку std::vector
:
struct VectorWrapper
{
virtual ~VectorWrapper() = 0;
};
template<typename T>
struct GenericVectorWrapper : public VectorWrapper
{
std::vector<T> vector;
~GenericVectorWrapper() {};
};
//This template class "builds" the search engine set (vector) of system data types vectors:
template<int type_index>
struct VectorBuilder
{
static void append_data_type_vector(std::vector<VectorWrapper*>& data)
{
data.push_back( new GenericVectorWrapper< system_data_types::type_at<type_index> >() ); //Pushes back a vector that stores the indexth type of system data.
VectorBuilder<type_index+1>::append_data_type_vector(data); //Recursive call
}
};
//Base case (End of the list of system data types)
template<>
struct VectorBuilder<system_data_types::size>
{
static void append_data_type_vector(std::vector<VectorWrapper*>& data) {}
};
Итак, реализация SearchEngine::_get_vector<T>
выглядит следующим образом:
template<typename T>
std::vector<T>& get_vector()
{
GenericVectorWrapper<T>* data; //Pointer to the corresponing vector
data = dynamic_cast<GenericVectorWrapper<T>*>(_data_lists[system_data_types::index_of<T>]); //We try a cast from pointer of wrapper-base-class to the expected type of vector wrapper
if( data )//If cast success, return a reference to the std::vector<T>
return data->vector;
else
throw; //Cast only fails if T is not a system data type. Note that if T is not a system data type, the cast result in a buffer overflow (index_of<T> returns -1)
}
Конструктор SearchEngine
использует VectorBuilder только для построения списка векторов:
SearchEngine()
{
VectorBuilder<0>::append_data_type_vector(_data_list);
}
И деструктор только перебирает список, удаляя векторы:
~SearchEngine()
{
for(unsigned int i = 0 ; i < system_data_types::size ; ++i)
delete _data_list[i];
}
Преимуществами данной конструкции являются:
Поисковая система использует один и тот же интерфейс для разных поисков (поиск с разными типами системных данных в качестве цели). И процесс «связывания» типа данных с соответствующими критериями поиска и результатами выполняется во время компиляции.
Этот интерфейс типобезопасен: вызов SearchEngine::search()
возвращает тип результатов, основанный только на переданных критериях поиска. Ошибки результатов назначения обнаруживаются во время компиляции. Например: NormalRoomResults = engine.search(LuxuryRoomCriteria())
вызывает ошибку компиляции (engine.search<LuxuryRoomCriteria>
возвращает LuxuryRoomResults
).
Поисковая система является полностью масштабируемой: чтобы добавить новый тип данных в систему, вам нужно только перейти к добавлению типов в списки типов. Реализация поисковой системы не меняется.
person
Manu343726
schedule
16.06.2013
typeid(aRoom)==typeid(openRooms[i])
всегда будет успешным, потому чтоaRoom
являетсяRoom*
, аopenRooms
содержит элементы типаRoom*
. Поэтому вы можете просто заменитьif(typeid(aRoom)==typeid(openRooms[i]))
наif(true)
. - person Oswald   schedule 16.06.2013tyepid
разрешит значение, соответствующее АКТУАЛЬНОМУ типу аргумента. - person Mats Petersson   schedule 16.06.2013Room*
является фактическим типом. Если вы хотите проверить, имеют ли комнаты, на которые указывают ваши указатели, разные типы среды выполнения, вы должны проверить,typeid(*aRoom)==typeid(*openRooms[i])
- person Oswald   schedule 16.06.2013typeid
в порядке, учитывая другие проблемы здесь. Вы должны использоватьlist
вместоvector
, так как комнаты должны открываться и закрываться, что означает, что вашopenRooms
участник изменится. Поскольку при бронировании отеля будет выполняться много поисков, вам также следует подумать о том, чтобы класс вашего отеля был оптимизирован для поиска, например, используяhash_map
сtype_info
в качестве ключа иlist
открытых номеров для этого типа в качестве значения. . - person Alan   schedule 16.06.2013typeid
- это худшее решение, которое только можно себе представить. Он маскирует атрибут в типе, что является плохим дизайном и, мягко говоря, сбивает с толку. - person James Kanze   schedule 16.06.2013matches( Criteria const& other ) const
). - person James Kanze   schedule 17.06.2013