C++:NVI和模板方法模式之间的区别?

Rob*_*nes 7 c++ design-patterns non-virtual-interface template-method-pattern

NVI(非虚拟接口)和模板方法模式之间有什么区别?

它们看起来非常相似,而且我已经读到它们基本相同,并且它们与模板在某种程度上更为通用有些微妙的不同.

Pet*_*ham 12

NVI是一种成语,模板方法是一种模式.NVI是使用C++中的动态分派的模板方法模式的实现; 也可以使用模板元编程在C++中创建模板方法,以消除动态调度.

模式比成语更通用,语言可以使用不同的习语来实现模式.

  • 所以你是说 NVI 基本上是模板方法模式的语言特定实现,除此之外没有真正的区别?您将如何使用 C++ 模板来实现相同的结果? (2认同)

Mat*_* M. 9

如前所述,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;
};
Run Code Online (Sandbox Code Playgroud)

并为实施:

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

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

我总是发现它更好地传达了这一点.你弄清楚了吗?

重点是这virtual是一个实现细节.在界面中公开实现细节是个坏主意,因为您可能希望更改它们.

此外,实现细节往往会混淆二进制兼容性.例如virtual,在类中添加新方法可能会更改虚拟表的布局(常见的实现技术),从而破坏二进制兼容性.在gcc上,如果您希望保持兼容性,则需要确保最后添加它(在虚拟中).

通过使用上面的NVI + Pimpl组合,virtual暴露的类中根本没有(甚至不是私有).内存布局是向后和向前兼容的.我们实现了二进制兼容性.

在这里,我们一次使用几种模式:

  • 模板方法
  • 策略(因为我们可以随意交换指针)
  • 工厂(决定我们得到的实施)