Ho letto alcune domande su SO e altrove e ancora non capisco bene dove questo "allargamento" di un tipo di parametro può essere utile, ad esempio il rispetto del principio di sostituzione di Liskov. Il seguente codice ho preso da una risposta sul SO, spiegando la controvarianza:
//Contravariance of parameter types: OK
class Food
class FastFood extends Food
class Person { eat(FastFood food) }
class FatPerson extends Person { eat(Food food) }
Quindi capisco che il metodo sottoposto a override accetta un parametro più generico rispetto al metodo nel suo antenato. Ma in pratica, come aiuta? Voglio dire, se il metodo originale funziona con certe proprietà del tipo derivato, niente di questo sarà disponibile nella derivata usando il supertipo del parametro. Pertanto, potrei avere problemi con l'adempimento delle post-condizioni del contratto, se quelle si riferiscono al sottotipo in qualche modo. Come:
class Animal {}
class Cat { void Meow() void CatSpecificThing()}
...
class A
{
List<Cat> ListOfCats;
void X(Cat c)
{
c.Meow()
c.CatSpecificThings()
ListOfCats.Add(c)
}
}
class B : A
{
void X(Animal a)
{
//how is this now useful? I cannot do anything that needed Cat
}
}
Supponiamo che la post-condizione del metodo X sia quella di aggiornare ListOfCats. Ma nel metodo sovrascritto nella classe derivata, non sarei in grado di farlo se ci fosse solo il supertipo ..?
Sarei estremamente felice per un semplice esempio che dimostra come sia utile.