在设计接口时,有人建议使用非虚拟接口模式。请简要概述一下这种模式的好处是什么?
在设计接口时,有人建议使用非虚拟接口模式。请简要概述一下这种模式的好处是什么?
非虚拟接口模式的本质是有私有虚拟函数,这些函数由公共非虚拟函数(即非虚拟接口)调用。
优点是基类对其行为有更多的控制,而不是派生类能够覆盖其界面的任何部分。换句话说,基类(接口)可以提供更多关于其功能的保证。
以一个简单的例子来说,考虑一个具有几个典型派生类的经典动物类:
class Animal
{
public:
virtual void speak() const = 0;
};
class Dog : public Animal
{
public:
void speak() const { std::cout << "Woof!" << std::endl; }
};
class Cat : public Animal
{
public:
void speak() const { std::cout << "Meow!" << std::endl; }
};
这个代码使用了我们习惯的公共虚拟接口,但有一些问题:
std::cout << ... << std::endl;
代码。speak()
函数的行为。一个派生类可能会忘记换行符,或者将其写到 cerr
或任何其他地方。要解决这个问题,可以使用非虚拟接口,并补充一个私有虚拟函数以实现多态行为:
class Animal
{
public:
void speak() const { std::cout << getSound() << std::endl; }
private:
virtual std::string getSound() const = 0;
};
class Dog : public Animal
{
private:
std::string getSound() const { return "Woof!"; }
};
class Cat : public Animal
{
private:
std::string getSound() const { return "Meow!"; }
};
现在,基类可以保证将输出到std::cout
并以新行结束。这也使得维护更容易,因为派生类不需要重复该代码。
Herb Sutter撰写了一篇有关非虚接口的好文章,我推荐阅读。
return
语句之前仍然可以做“任何他们想做的事情”,这是否仍然成立?我猜测,这个问题的答案很简单,即NVI模式并不旨在保护免受故意的糟糕设计选择的影响,但如果您能发表一下您的看法,那将是很好的。 - Enlico