Как и в большинстве случаев, когда дело доходит до выбора подходящей архитектуры системы, ответ «это зависит» :).Наиболее удобным решением было бы ввести специфичное для протокола поведение подклассов ProtocolBase
в их конструкторах
class ProtocolV2 : public ProtocolBase
{
public:
ProtocolV2::ProtocolV2(args) {
// set some params that will determine when do_V2() is called
// it can be some numeric setting, a callback, or similar
}
void set_parameters() override {
// you can use V2 behavior here maybe?
std::cout << "set parameters for V2" << std::endl;
}
void reset_parameters() override {
// or here maybe?
std::cout << "reset parameters for V2" << std::endl;
}
private:
void do_V2() {
std::cout << "doing V2" << std::endl;
}
};
Если по какой-либо причине вы не можете сделать это, есть возможность сохранить do_V2()
как общедоступныйне виртуальный метод, но вызывать его перед передачей ProtocolV2
в качестве указателя на ProtocolBase
системной системе, которая будет его использовать.Конечно, ограничение заключается в том, что do_V2
можно вызывать только за пределами области вашей системы, что не может реально решить проблему.
Другой вариант - фактически переместить do_V2()
в интерфейс:
class ProtocolBase {
public:
virtual void reset_parameters() {
std::cout << "reset parameters" << std::endl;
}
virtual void set_parameters() {
std::cout << "set parameters" << std::endl;
}
virtual void do_V2() {
std::cout << "not supported" << std::endl;
}
};
и реализовать его как «не поддерживаемое» поведение по умолчанию.Только ProtocolV2
будет реализовывать это поведение в качестве допустимой части протокола.
В конце концов, если ничего из вышеперечисленного не подходит, вы, конечно, можете использовать dynamic_cast, как вы предложили.Лично я стараюсь избегать dynamic_cast
, потому что мои коллеги по офису наверняка начнут злоупотреблять им, но в некоторых случаях это правильное решение.
Также, если вы решите навести указатель, используйте std::shared_ptr
сdynamic_pointer_cast
вместо доступа к необработанному указателю из unique_ptr
.