What's Liskov Substitution Principle?

Liskov Substitution Principle (LSP) was first introduced by Barbara Liskov in 1988. The idea revolves around the principle of “substitutability” that explains the notion of strong behavioral subtyping. It is the semantic relation between classes (a parent class and its child class).

Liskov Substitution Principle states that the object of a derived class can substitute the object of the base class without affecting the whole software.

The idea is that the derived class should have characteristics similar to its parent class (base class). These characteristics include the return type and arguments passed to the functions.

LSP put forward some standard requirements regarding type annotations (input or output of a function, method) and type signatures (function overloading, etc.):

  • Covariance and contravariance must be applied in the subclass.
  • If an exception occurs, a subclass cannot throw more exceptions.

Other than the syntactic requirements of LSP, there are a few conditions that must be followed related to the behavior of base and derived classes:

  • All pre-conditions and post-conditions in the subclass must be strictly followed as in the superclass.
  • It is necessary to maintain invariants in the subclass as in the superclass.

In the inheritance structure, Liskov’s Substitution Principle ensures that when a user makes changes in the software, the object of the child class is used, and the user stays unaware. The behavior of both classes should be the same.

A flowchart example of inheritance and LSP

Examples

#include <iostream>
using namespace std;
class Animals
{
public:
void layEggs()
{
cout<<"Reptiles Lay eggs"<<endl;
}
};
class dog : public Animals
{
};
int main()
{
dog obj;
obj.layEggs();
}

The above example is not an ideal example. It is not a characteristic of dogs to lay eggs, so using the object of the dog class to use the function layEggs() will break the LSP, because both classes do not share the same behavior.

#include <iostream>
using namespace std;
class Animals{
public:
void reproduce();
};
class Reptiles:Animals
{
public:
void layEggs()
{
cout<<"Reptiles Lay eggs"<<endl;
}
};
class snake : public Reptiles{
};
class dog : public Animals{
};
int main() {
snake obj;
obj.layEggs();
}

This is a good example. We created a new class Reptiles that inherits the class Animals and contains the function layEggs(). And now, the class snake can inherit the class Reptiles. And similarly, the object of class dog can be used in place of the object of class Animals because they share the same behavior. So, if we create an object of the derived class instead of the base class, it will not disturb the application and the LSP.

Free Resources

Copyright ©2025 Educative, Inc. All rights reserved