Объясню в 2 словах, что это такое:
DbC: функции снабжаются предусловиями(preconditions) и постусловиями(postconditions). Своё выполнение функция начинает только, если предусловия удовлетворены. После своего завершения фукнция гарантирует, что постусловия и инварианты класса будут соблюдены/непротиворечивы.
LSP — это один из способов определения того, может ли быть один класс подтипом другого. Основывается на отношении IS-A. Только не в плане внешнего сходства классов, а в плане их поведенческой заменяемости при использовании ссылки на базовый класс объекта производного класса.
На примере кода покажу, почему нельзя класс Человек(Human) наследовать от класса Камин(Fireplace).
#include <iostream>
#include <cassert>
class Fireplace {
public:
// средняя температура камина без дров (т.е. кирпича внутри него) 18 градусов
Fireplace() : temperature(18) { }
// функция-гетер
int getTemperature() const {
return temperature;
}
// функция-сетер
void setTemperature(int N) {
temperature = N;
}
// подогреть на N градусов
virtual void heat(int N) {
// preconditions
int old_temperature = getTemperature();
// кирпич в камине выдерживает максимум 800 градусов Цельсия
assert(getTemperature() + N < 800);
std::cout << "Подбросали дровишек";
setTemperature(getTemperature() + N);
// postconditions
// новая температура должна быть равна старой + N
assert(getTemperature() == old_temperature + N);
}
private:
int temperature;
};
class Human : public Fireplace {
public:
Human() { setTemperature(36); }
virtual void heat(int N) {
// preconditions
int old_temperature = getTemperature();
assert(getTemperature() + N < 800); // этот assert не имеет смысла, т.к.
// 800 градусов - многовато для человека
// человек максимум может нагреться на 45 градусов
// но мы не имеем права определить такой assert:
// assert(getTemperature() + N < 45);
// иначе мы бы УСИЛИЛИ предусловие и произошло бы
// нарушение контракта базового класса!
// Правила DbC:
// 1) предусловия в производных классах можно только ослаблять, но не усиливать
// 2) Постусловия можно усиливать, но не ослаблять
// следовательно - класс Human не может быть подтипом Fireplace
// т.к. помимо нарушется контракта нарушается сам принцип LSP,
// согласно которому объекты базовых/произвдных должны быть
// поведенчески эквивалентными и взаимозаменяемыми
std::cout << "Выпил водки";
setTemperature(getTemperature() + N);
// postconditions базового класса. не изменяем ничего в них.
// новая температура должна быть равна старой + N
assert(getTemperature() == old_temperature + N);
}
};
int main()
{
Fireplace *f = new Human;
f->heat(600);
return 0;
}
* This source code was highlighted with Source Code Highlighter.Кстати, если бы камин мог нагреваться только до 45 градусов — то он бы мог с точки зрения LSP быть подтипом Fireplace :)
Буду рад, если статья кому-нибудь помогла, немножко прояснила эти принципы.

