Лучшее решение
Основываясь на комментарии @ ALX23z о недействительности ссылки на переменную-член при перемещении, я сейчас отклоняю свое первоначальное решение (исходное сообщение). Эта проблема недействительности не была бы проблемой для моего случая, но я нахожусь в поиске универсального c шаблона.
Как обычно, решение становится очевидным, как только его найдут.
Сначала краткий обзор моей первоначальной проблемы.
Скажите, что у меня есть интерфейс программы обновления программного обеспечения (или любой интерфейс, это только пример):
class Software_updater {
virtual ~Software_updater() = default;
virtual void action1(const Input1& input1) = 0;
virtual void action2() = 0;
virtual bool action3(const Input2& input2) = 0;
virtual Data1 info1() = 0;
virtual Data2 info2() = 0;
// etc.
};
A B_software_updater
может обновить два images: образ приложения и образ загрузчика. Поэтому он хочет предоставить два экземпляра интерфейса Software_updater
.
Решение, которое лучше, чем в моем исходном посте, состоит в объявлении B_application_updater
и B_boot_loader_updater
, созданных из B_software_updater&
, вне B_software_updater
, и реализуется клиентским кодом.
class B_application_updater : public Software_updater {
B_application_updater(B_software_updater&);
// ...
};
class B_boot_loader_updater : public Software_updater {
B_application_updater(B_boot_loader_updater&);
// ...
};
Недостатком является то, что клиентский код вынужден создавать три объекта вместо одного, но я думаю, что чистота перевешивает этот недостаток.
Это будет работать и для дополнительного интерфейса (см. исходное сообщение):
class A_optional_implementation : public Optional_interface {
A_optional_implementation(A_implementation&);
};
A_optional_implementation
будет объявлено за пределами A_implementation
.
Приложения, которые не нуждаются в этом интерфейсе, просто не будут создавать экземпляры A_optional_implementation
.
Дополнительные мысли
Это приложение шаблона проектирования адаптера!
По сути, что это за ответ сводится к:
- класс
Interface
. - класс
Implementation
, который выполняет работу, но на самом деле не заботится об интерфейсе. Он не наследует Interface
. Дело в том, что Implementation
может «выполнять работу», соответствующую нескольким интерфейсам, без сложности и недостатков множественного наследования (конфликты имен и т. Д. c.). Он также может выполнять работу, соответствующую нескольким экземплярам одного и того же интерфейса (мой случай выше). - Класс
Interface_adapter
, который принимает параметр Implementation&
в своем конструкторе. Он наследует Interface
, то есть эффективно реализует его, и это его единственная цель.
Делая шаг назад, я понимаю, что это просто приложение шаблона адаптера (хотя Implementation
в этом случае не обязательно реализовывать какой-либо внешний интерфейс - его интерфейс - это просто его публичные c функции-члены)!
Промежуточное решение: оставить классы адаптера внутри реализации class
В приведенном выше решении я указываю, что классы адаптера объявляются вне классов реализации. Хотя это кажется логичным для случая с традиционным шаблоном адаптера, для моего случая я мог бы также объявить их внутри класса реализации (как я это делал в исходном посте) и сделать их опубликованными c. Клиентскому коду все равно придется создавать объекты реализации и адаптера, но классы адаптера будут принадлежать пространству имен реализации, которое выглядит лучше.