When designing an interface, som开发者_Go百科eone recommended to use the non-virtual interface pattern. Can someone briefly outline what the benefits of this pattern are?
The essence of the non-virtual interface pattern is that you have private virtual functions, which are called by public non-virtual functions (the non-virtual interface).
The advantage of this is that the base class has more control over its behaviour than it would if derived classes were able to override any part of its interface. In other words, the base class (the interface) can provide more guarantees about the functionality it provides.
As a simple example, consider the good old animal class with a couple of typical derived classes:
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; }
};
This uses the usual public virtual interface that we're used to, but it has a couple of problems:
- Each derived animal is repeating code -- the only part that changes is the string, yet each derived class needs the whole
std::cout << ... << std::endl;
boilerplate code. - The base class can't make guarantees about what
speak()
does. A derived class may forget the new line, or write it tocerr
or anything for that matter.
To fix this, you can use a non-virtual interface that is supplemented by a private virtual function that allows polymorphic behaviour:
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!"; }
};
Now the base class can guarantee that it will write out to std::cout
and end with a new line. It also makes maintenance easier as derived classes don't need to repeat that code.
Herb Sutter wrote a good article on non-virtual interfaces that I would recommend checking out.
Here is a wiki article it a bit more in details with some examples. The essence is that you can ensure important conditions (like obtaining and releasing locks) in a central place in your base class while still allowing to derive from it to provide different implementations by using private or protected virtual functions.
Users of any class of the class hierarchy will always call the public interface which dispatches the calls to the not externally visible implementations.
精彩评论