Как уже было сказано, 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 (решить, реализация которых мы получаем)
Я бы не использовал ссылку на wikipedia в качестве ссылки, их использование замков является хрупким перед лицом исключений ... –