Используйте иерархии классов для представления концепций с присущей иерархической структурой (только)
Причина
Прямое представление идей в коде облегчает понимание и обслуживание. Убедитесь, что идея, представленная в базовом классе, точно соответствует всем производным типам и нет лучшего способа выразить её, чем использование тесной связи наследования.
Не используйте наследование, когда просто наличие члена данных будет достаточным. Обычно это означает, что производный тип должен переопределить виртуальную функцию базового класса или нужен доступ к защищённому члену.
Пример
class DrawableUIElement {
public:
virtual void render() const = 0;
// ...
};
class AbstractButton : public DrawableUIElement {
public:
virtual void onClick() = 0;
// ...
};
class PushButton : public AbstractButton {
void render() const override;
void onClick() override;
// ...
};
class Checkbox : public AbstractButton {
// ...
};
Пример, плохой
Не представляйте нежирархические концепции домена как иерархии классов.
template<typename T>
class Container {
public:
// операции списка:
virtual T& get() = 0;
virtual void put(T&) = 0;
virtual void insert(Position) = 0;
// ...
// операции вектора:
virtual T& operator[](int) = 0;
virtual void sort() = 0;
// ...
// операции дерева:
virtual void balance() = 0;
// ...
};
Здесь большинство переопределяющих классов не могут адекватно реализовать большинство функций, требуемых в интерфейсе. Таким образом, базовый класс становится бременем реализации. Кроме того, пользователь Container не может полагаться на то, что функции-члены фактически выполняют значимые операции достаточно эффективно; они могут вместо этого выбросить исключение. Таким образом, пользователи должны прибегать к проверкам во время выполнения и/или не использовать этот (чрезмерно) общий интерфейс в пользу конкретного интерфейса, найденного путём запроса типа во время выполнения (например, dynamic_cast).
Применение
- Ищите классы с множеством членов, которые ничего не делают, кроме как выбрасывают исключение.
- Помечайте каждое использование невежественного базового класса
B, где производный классDне переопределяет виртуальную функцию и не получает доступ к защищённому члену вB, иBне является одним из следующих: пусто, параметр шаблона или пакет параметровD, шаблон класса специализированный сD.