I’m trying to follow LSP in practical programming. And I wonder if different constructors of subclasses violate it. It would be great to hear an explanation instead of just yes/no. Thanks much!
P.S. If the answer is no
, how do I make different strategies with different input without violating LSP?
class IStrategy
{
public:
virtual void use() = 0;
};
class FooStrategy : public IStrategy
{
public:
FooStrategy(A a, B b) { c = /* some operations with a, b */ }
virtual void use() { std::cout << c; }
private:
C c;
};
class BarStrategy : public IStrategy
{
public:
BarStrategy(D d, E e) { f = /* some operations with d, e */ }
virtual void use() { std::cout << f; }
private:
F f;
};
1
Generally constructors are not considered to be part of the Liskov substitution Principle (LSP). The LSP with objects, not classes:
What is wanted here is something like the following substitution property: If
for each object o1 of type S there is an object o2 of type T such that for all
programs P defined in terms of T, the behavior of P is unchanged when o1 is
substituted for o2 then S is a subtype of T. (quoted this PDF file)
Since an object doesn’t exist until after construction, the constructor itself is generally consider to be out of scope. The LSP wants all subclasses to behave the same. How they get to that behaviour is a different matter.
This means you’re code example is not in violation of the LSP per se. The constructor and the private methods are not part of the public contract when viewed from a LSP perspective.
Do keep in mind that LSP goes a lot further than function signatures. If a parent throws an exception in a specific case, so should the children. If a parent doesn’t children can’t start throwing execptions all of a sudden, if a getStock function in a parent returns an integer, a child can’t start returning stock objects, etc, etc
The LSP deals with every aspect of public behaviour an object has.
A common solution to creating strategies with different constructors is the factory pattern by the way.
4
TL;DR: Different subtype constructors are not only ok, they are expected.
Liskov directly addresses the usage of different constructors in her paper Behavioral Subtyping Using Invariants and Constraints which is the formalization of the principle.
“..omitting creators [from the type specification] makes it easy for a type to have multiple implementations, allows new creators to be added later, and reflects common usage”
This then shows that alternative constructors in the subtype are not only okay, but expected. It is also further addressed explicitly in the summary of the paper.