C++: Разница между шаблонами NVI и шаблонами?

В чем разница между шаблонами NVI ( не виртуальный интерфейс) и шаблонным методом?

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

2 ответа

Решение

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

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

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

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

Однако реализация может на самом деле значительно отличаться, например, другой пример реализации 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 на всех (даже не частных) в классе выставлено. Расположение памяти обратно и вперед совместимо. Мы достигли бинарной совместимости.

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

  • Шаблонный метод
  • Стратегия (так как мы можем поменять указатель по желанию)
  • Фабрика (чтобы решить, какую реализацию мы получим)
Другие вопросы по тегам