Почему Boost Parameter выбирает наследование, а не состав?

Я предполагаю, что большинство людей на этом сайте согласятся, что реализация может быть передана на аутсорсинг двумя способами:

  • частное наследство
  • состав

Наследование чаще всего злоупотребляют. Примечательно, что публичное наследование часто используется, когда другая форма или наследование могло бы быть лучше, и в целом следует использовать композицию, а не частное наследование.

Конечно, применяются обычные предостережения, но я не могу вспомнить ни одного момента, когда мне действительно нужно наследование для проблемы реализации.

Однако для библиотеки Boost Parameter вы заметите, что они выбрали наследование, а не композицию для реализации именованного параметра idiom (для конструктора).

Я могу думать только о классическом объяснении EBO (Empty Base Optimization), поскольку здесь нет виртуальных методов, которые я вижу.

Кто-нибудь знает лучше или может перенаправить меня на обсуждение?

Спасибо, Матье.

2 ответа

Решение

РЕДАКТИРОВАТЬ: Ooopss! Я разместил ответ ниже, потому что я неправильно прочитал ваш пост. Я думал, вы сказали, что библиотека Boost использует композицию вместо наследования, а не наоборот. Тем не менее, если это полезно для кого-либо... (См. EDIT2 для того, что я думаю, может быть ответом на ваш вопрос.)

Я не знаю конкретного ответа для библиотеки параметров Boost. Тем не менее, я могу сказать, что обычно это лучший выбор. Причина в том, что всякий раз, когда у вас есть возможность реализовать отношения более чем одним способом, вы должны выбрать самый слабый (низкая связь / высокая сплоченность). Так как наследство сильнее, чем композиция...

Обратите внимание, что иногда использование частного наследования может усложнить реализацию кода, исключающего исключения. принимать operator==, например. Используя композицию, вы можете создать временное и выполнить назначение с логикой фиксации / отката (при условии правильного построения объекта). Но если вы используете наследование, вы, вероятно, будете делать что-то вроде Base::operator==(obj) внутри operator== производного класса. Если это Base::operator==(obj) броски вызовов, вы рискуете своими гарантиями.

РЕДАКТИРОВАТЬ 2: Теперь, пытаясь ответить на то, что вы действительно спросили. Это то, что я мог понять из ссылки, которую вы предоставили. Поскольку я не знаю всех деталей библиотеки, пожалуйста, поправьте меня, если я ошибаюсь.

Когда вы используете композицию для "реализовано в терминах", вам нужен один уровень косвенности для делегирования.


struct AImpl 
{ 
  //Dummy code, just for the example.
  int get_int() const { return 10; }
};

struct A { AImpl * impl_; int get_int() const { return impl->get_int(); } /* ... */ };

В случае конструктора с включенным параметром вам необходимо создать класс реализации, но вы все равно должны иметь возможность использовать класс "оболочки" прозрачным способом. Это означает, что в примере по ссылке, которую вы упомянули, желательно, чтобы вы могли манипулировать myclass так же, как вы бы манипулировать myclass_impl, Это может быть сделано только через наследование. (Обратите внимание, что в этом примере наследование является общедоступным, поскольку оно используется по умолчанию для структуры.)

Я предполагаю myclass_impl Предполагается, что это "реальный" класс, класс с данными, поведением и т. д. Затем, если у вас есть такой метод, как get_int() в нем, и если вы не используете наследование, вы будете вынуждены написать get_int() обертка в myclass так же, как я сделал выше.

Это не та библиотека, которую я когда-либо использовал, поэтому просмотр документации, на которую вы ссылаетесь, - единственное, на чем я основываю этот ответ. Вполне возможно, что я собираюсь ошибаться, но...

Они упоминают делегирование конструктора как причину использования общего базового класса. Вы правы, что композиция может решить и эту проблему. Однако поместить все это в один тип не получится. Они хотят объединить несколько сигнатур конструктора в одну пользовательскую функцию инициализации и без делегирования конструктора, который требует второго типа данных. Я подозреваю, что большая часть библиотеки уже была написана с точки зрения помещения всего в сам класс. Когда они столкнулись с проблемой делегирования конструктора, они пошли на компромисс. Помещение его в базовый класс, вероятно, было ближе к тому, что они делали с предыдущей функциональностью, где они знали, что аспекты интерфейса и реализации функциональности будут доступны для класса, с которым вы работаете.

Я никоим образом не захлопываю библиотеку. Я очень сомневаюсь, что смогу собрать подобную библиотеку за любое разумное время. Я просто читаю между строк. Вы знаете, говоря по невежеству, но притворяясь, что я действительно что-то знаю:-)

Другие вопросы по тегам