Суть невиртуального шаблона интерфейса состоит в том, что у вас есть частные виртуальные функции, которые вызываются общедоступными не виртуальными функциями (не виртуальный интерфейс).
Преимущество этого состоит в том, что базовый класс имеет больший контроль над своим поведением, чем если бы производные классы могли переопределять любую часть своего интерфейса.Другими словами, базовый класс (интерфейс) может предоставить больше гарантий относительно функциональности, которую он обеспечивает.
В качестве простого примера рассмотрим старый добрый класс животных с парой типичных производных классов:
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
и завершится новой строкой.Это также облегчает обслуживание, поскольку производным классам не нужно повторять этот код.
Херб Саттер написал хорошую статью о не виртуальных интерфейсах , которую я бы рекомендовал проверить.