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