В моей системе низкоуровневые объекты взаимодействуют с высокоуровневым объектом посредством вызова функции высокоуровневого объекта +1 уровня, которая вызывает функцию высокоуровневого объекта +1 уровня и т. Д. И т. Д., Пока вызов функции не остановится у получателя.
Существует абстрактный класс Message, и есть много производных классов, которые содержат различные типы данных.
Подобно:
FruitMessage: строка, int
CoordinateMessage: плавать, плавать, плавать
и т. д.
И те методы, о которых я упоминал ранее, нуждаются в объектах Message, так что это согласование выполняется с помощью одного вида методов вместо создания методов для всех типов сообщений.
Проблема возникает, когда получатель получает объект сообщения.
Получатель хочет знать что в этом сообщении, так может процесс получает сообщение, как того требует тип сообщения.
(как это уменьшает целое число на 1 в FruitMessages, делит координаты в CoordinateMessages и т. д.)
В настоящее время у меня есть две идеи, но, возможно, ни одна из них не верна, и я должен использовать третью. (скажи мне, пожалуйста)
Получатель dynamic_casts это пока он не имеет правильный тип.
Сообщение имеет поле перечисления с именем MessageType, которое инициализируется в конструкторе производного класса до правильного значения, поэтому получатель просто использует регистр переключения во время процесса.
У меня вопрос, стоит ли резервирование?
dynamic_cast медленнее, чем целочисленная проверка
но каждый раз, когда я создаю новый класс Message, мне нужно создавать новое значение перечисления.
Что я должен делать?
Оба способа в порядке. Избыточность в зависимости от скорости является очень распространенной проблемой при разработке программного обеспечения.
Я бы выбрал dynamic_cast, так как избыточность — это первый шаг к ошибкам, но это действительно зависит от вас и зависит от ваших требований к производительности.
Я видел очень похожую проблему при работе с Akka, они обычно используют dynamic_cast (я имею в виду аналоги java / scala)
Я бы порекомендовал использовать typeid
Оператор, чтобы проверить тип сообщения. Таким образом, вы избегаете повторного вызова dynamic_cast
пока вы не получите правильный тип.
void process_message(Message const& msg) {
if (typeid(msg) == typeid(FruitMessage)) {
auto& fruit_msg = static_cast<FruitMessage const&>(msg);
…
}
}
Еще лучше, вы могли бы использовать C ++ 17 std::any
Тип контейнера. any
Объект может быть скопирован как неполиморфное значение, и не требует использования виртуального базового класса. Если у вас нет доступа к реализации библиотеки C ++ 17, вы можете использовать boost::any
вместо.
void process_message(std::any const& msg) {
if (msg.type() == typeid(FruitMessage)) {
auto fruit_msg = std::any_cast<FruitMessage>(msg);
…
}
}
Что касается использования enum
поле будет быстрее, чем typeid
или же any
, вам придется сделать бенчмаркинг самостоятельно.