Behavioral subtyping is the principle that subclasses should satisfy the expectations of clients accessing subclass objects through references of the superclass type.
For example, in C++:
class X {};
class Y : public X {};
* x = Y{}; X
Y should be treatable as its superclass(es), but it must also retain its behavioral (implied) characteristics.
For example, if the Bag classes interface supports a get and a put, where the get pops and returns a random item from the collection, and put places an item in the bag, then if we subclass Bag with Queue and Stack types, that’s fine – we can treat Stacks and Queues as Bags.
class Bag {
int get() = 0; // get random item from collection
void put(int x) = 0; // put item in bag
};
class Queue : public Bag {
int get() { return item.popleft(); }
void put(int x) { item.push_back(x); }
};
class Stack : public Bag {
int get() { return item.pop(); }
void put(int x) { item.push_back(x); }
};
* s = new Stack(); // this is fine, because a stack and queue support
Bag// the implicit interface of a Bag.
However, if we subclass Queue from Stack or vice versa, stacks and queues would not work, as they don’t have the same characteristics (LIFO != FIFO).
This is an informal rule, but nonetheless is a good ideal to ascribe to.