7

В чем разница между NVI (Non-Virtual Interface) и шаблонами Template Method?C++: Разница между шаблонами методов NVI и шаблонов?

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

+1

Я бы не использовал ссылку на wikipedia в качестве ссылки, их использование замков является хрупким перед лицом исключений ... –

ответ

11

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

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

+1

Итак, вы говорите, что NVI - это в основном языковая реализация шаблона метода шаблонов, и кроме этого нет никакой реальной разницы? Как бы вы использовали шаблоны C++ для достижения того же результата? –

+0

@ Robert S. Barnes Насколько я вижу, нет очевидного способа использования шаблонов C++ в качестве метода шаблона. Метод шаблона говорит: «Сделайте это, а затем сделайте это другое», и хотя вы можете создать функтор для того или иного дела, нет реальных отношений с параметрами типа, которые дают вам шаблоны C++. –

+0

Я догадываюсь, что я все еще не понимаю, что вы имели в виду здесь: «также можно создавать шаблонные методы на C++, используя метапрограммирование шаблонов, чтобы исключить динамическую отправку». –

8

Как уже было сказано, NVI - это идиома прогейминга, относящаяся к категории языков. Это поощрялись Herb Sutter среди других, потому что это помогает обеспечению исполнению контрактов:

  • инвариантов класса
  • функции контракты (утверждение над параметрами, передаваемыми и возвращаемым значением генерируемого)
  • повторяющихся операций (как протоколирования)
  • контроль за исключением сгенерированных (плохая идея, хотя;))

Однако реализация может на самом деле значительно отличаются, например, другой пример NVI реализация сочетать его с Pimpl:

class FooImpl; 

class Foo 
{ 
public: 
    enum type { Type1, Type2 }; 

    Foo(type t, int i, int j); 

    int GetResult() const; 

private: 
    FooImpl* mImpl; 
}; 

И для реализации:

struct FooImpl 
{ 
    virtual ~FooImpl(); 
    virtual int GetResult() const; 
}; 

class FooType1: public FooImpl 
{ 
public: 
    FooType1(int i, int j); 
    virtual int GetResult() const; 
private: 
    /// ... 
}; 

Я всегда считал, что он передал дело лучше. Вы поняли это?

Главное, что virtual является деталью реализации. И разоблачение деталей реализации в интерфейсе - плохая идея, потому что вы можете изменить их.

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

При использовании комбинации NVI + Pimpl выше virtual на всех (даже не закрытых) в открытом классе. Макет памяти совместим с обратной связью. Мы достигли бинарной совместимости.

Здесь мы используем несколько моделей сразу:

  • Template Method
  • стратегии (так как мы можем поменять указатель по желанию)
  • Factory (решить, реализация которых мы получаем)
+0

+1 для «виртуальной детали реализации» и рассмотрения ABI. – neuro

+0

+1. Однако я должен не согласиться с вами о создании отдельных классов, подобных Pimpl для виртуального интерфейса. Наиболее очевидным недостатком является то, что он удваивает количество требуемых классов. Кроме того, если FooImpl не был непрозрачным, это может заставить собеседников использовать его напрямую и пропустить Foo. Однако маловероятно, что это будет непрозрачно, поскольку точка NVI должна позволить людям переопределять виртуальные реализации, поэтому FooImpl должен быть общедоступным. Несмотря на то, что у него есть свои недостатки, я думаю, что внедрение NVI в одном классе и исключение общих виртуальных функций - это лучший подход. – stinky472

+0

Это также более простая политика для обеспечения соблюдения: нет публичных виртуальных функций, а не одного, что делает специальные случаи для подобных PIMPL-классам, которые предоставляют публичный виртуальный интерфейс. – stinky472

Смежные вопросы