Интерфейс обратного вызова был предложен в нескольких других ответах, но он имеет недостатки:
- Множество (потенциально значительно) разных классов, использующих один и тот же интерфейс. Эти классы по-разному могут испортить ясность интерфейса. То, что началось с PlaySound (sound_name), становится PlaySound (строка sound_name, bool reverb, float max_level, vector direction, bool looping, ...) с помощью множества других методов (StopSound , RestartSound и т. Д.)
- Изменения в аудиоинтерфейсе перестроят все, что знает об аудиоинтерфейсе (я считаю, что это имеет значение с C ++)
- Предоставленный интерфейс работает только для аудиосистемы (ну, это должно быть только для аудиосистемы). А как насчет видеосистемы и сетевой системы?
Одна альтернатива, которая также была упомянута, - сделать вызовы аудиосистемы статическими (или интерфейс аудиосистемы одноэлементными). Это позволит упростить конструкцию собаки (создание собаки больше не требует знания аудиосистемы), но не решит ни одну из проблем, перечисленных выше.
Мое предпочтительное решение - делегаты. Собака определяет свой общий выходной интерфейс (IE Bark (t_barkData const & data); Growl (t_growlData const & data)), и другие классы подписываются на этот интерфейс. Системы делегатов могут стать довольно сложными, но при правильной реализации они не сложнее в отладке, чем интерфейс обратного вызова, сокращают время перекомпиляции и улучшают читаемость.
Важным примечанием является то, что выходной интерфейс собаки не обязательно должен быть отдельным классом, который предоставляется собаке при строительстве. Вместо этого указатели на функции-члены собаки могут кэшироваться и выполняться, когда собака решает, что она хочет лаять (или фигура решает нарисовать).
Отличной общей реализацией являются сигналы и слоты QT, но реализовать что-то столь мощное самостоятельно будет сложно. Если вам нужен простой пример чего-то подобного в c ++, я бы подумал опубликовать его, но если вам это не интересно, я не собираюсь тратить время на субботу:)
Некоторые недостатки для делегатов (от макушки головы):
1. Вызвать накладные расходы, для вещей, которые происходят тысячи раз в секунду (IE «рисует» операции в механизме рендеринга), это необходимо учитывать. Большинство реализаций медленнее, чем виртуальные функции. Эти накладные расходы совершенно незначительны для операций, которые происходят не очень часто.
2. Генерация кода, в основном ошибка ограниченной поддержки указателей в функциях C ++. Шаблоны - это практически требование для реализации легко читаемой переносимой системы делегатов.