Подтвердить что ты не робот

Должен ли я прекратить использование абстрактных базовых классов/интерфейсов и вместо этого использовать boost:: function/std:: function?

Я только что узнал о том, что такое std:: function, и о том, для чего он используется, и у меня есть вопрос: теперь, когда мы по существу имеем делегаты, где и когда следует использовать абстрактные базовые классы и когда вместо этого, мы должны реализовать полиморфизм через объекты std:: function, переданные в общий класс? Возникла ли ABC смертельный удар в С++ 11?

Лично мой опыт до сих пор заключается в том, что переключение делегатов намного проще в кодировании, чем создание нескольких унаследованных классов для конкретного поведения... поэтому я немного запутался в том, насколько полезны абстрактные базы.

4b9b3361

Ответ 1

Предпочитают хорошо определенные интерфейсы над обратными вызовами

Проблема с std::function (ранее boost::function) заключается в том, что большую часть времени вам нужно иметь обратный вызов методу класса и, следовательно, необходимо привязать this к объекту функции. Однако в вызывающем коде вы не можете узнать, существует ли еще this. На самом деле, вы даже не подозреваете, что даже существует this, потому что bind сформировал подпись вызывающей функции в том, что требует вызывающий.

Это может привести к возникновению странных сбоев, поскольку обратный вызов пытается запустить методы для классов, которые больше не существуют.

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

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

Дополнительная проблема с std::function заключается в том, что многие отладчики не поддерживают их хорошо. В VS2008 и повышающих функциях вам нужно пройти около 7 уровней, чтобы перейти к вашей функции. Даже если все остальные вещи равны обратному результату, лучший выбор, явное раздражение и время, потраченное впустую, случайно перешагнув цель std::function, являются достаточной причиной, чтобы избежать этого. Наследование является основной особенностью языка, и переход к переопределенному методу интерфейса является мгновенным.

Наконец, я просто добавлю , у нас нет делегатов в С++. Делегаты в С# являются основной частью языка, так же как наследование - на С++ и С#. У нас есть функция std library, IMO - один слой, удаленный из функциональности основного языка. Таким образом, он не будет столь тесно интегрирован с другими основными функциями языка. Вместо этого он помогает формализовать идею объектных объектов, которые были идиомой С++ в настоящее время.

Ответ 2

Я не вижу, как можно прийти к выводу, что указатели на функции делают абстрактные базовые классы устаревшими.

Класс, инкапсулирует методы и данные, относящиеся к нему.

Указатель функции - это указатель на функцию. Он не имеет понятия об инкапсулирующем объекте, он просто знает о переданных ему параметрах.

Когда мы пишем классы, мы описываем четко определенные объекты.

Указатели функций отлично подходят для большого количества вещей, но изменение поведения объекта необязательно является целевой аудиторией (хотя я допускаю, что могут быть моменты, когда вы захотите это сделать, например, обратные вызовы, как Doug.T).

Пожалуйста, не путайте их.