Ключевое
Принцип подстановки Лисков (Liskov Substitution Principle, LSP) утверждает, что объекты в программе должны быть заменяемы экземплярами их подтипов без изменения корректности программы.
(довольно мутные) Требования
- Контракт родительского класса - подкласс должен соблюдать контракт суперкласса (все публичные методы должны работать аналогично).
- Семантическое поведение - поведение методов подкласса должно быть согласовано с поведением методов суперкласса.
- Инварианты - подклассы должны поддерживать инварианты (неизменные состояния) суперкласса.
- Пост- и предусловия - подклассы не должны усиливать предусловия (условия до выполнения метода) и ослаблять постусловия (условия после выполнения метода) суперкласса.
Пример
class Rectangle {
public:
virtual void setWidth(double width) {
this->width = width;
}
virtual void setHeight(double height) {
this->height = height;
}
double getArea() const {
return width * height;
}
protected:
double width;
double height;
};
class Square : public Rectangle {
public:
void setWidth(double width) override {
this->width = width;
this->height = width;
}
void setHeight(double height) override {
this->width = height;
this->height = height;
}
};
Проблема:
- Если заменить
Rectangle
наSquare
, изменив ширину, также изменится и высота, что нарушает ожидания отRectangle
. Это нарушение LSP, так как изменяется контракт суперкласса.