在设计界面时,有人建议使用非虚拟界面模式。有人可以简要概述这种模式的好处是什么吗?
问问题
6791 次
2 回答
50
非虚拟接口模式的本质是你有私有的虚拟函数,它们被公共的非虚拟函数(非虚拟接口)调用。
这样做的好处是,与派生类能够覆盖其接口的任何部分相比,基类对其行为有更多的控制。换句话说,基类(接口)可以为其提供的功能提供更多保证。
作为一个简单的例子,考虑具有几个典型派生类的良好的旧动物类:
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 写了一篇关于非虚拟接口的好文章,我建议您查看一下。
于 2011-06-26T00:12:50.787 回答
4
这是一篇wiki 文章,其中包含一些示例,其中包含更多详细信息。本质是您可以在基类的中心位置确保重要条件(如获取和释放锁),同时仍然允许从基类派生以通过使用私有或受保护的虚函数来提供不同的实现。
类层次结构的任何类的用户将始终调用公共接口,该接口将调用分派给外部不可见的实现。
于 2011-06-26T00:20:54.510 回答