Si C++ avait pleine covariance et le soutien de contravariance, la relation correcte serait contravariante en entrée et covariant en sortie. A savoir:
struct Organism { };
struct Animal : Organism {
virtual Animal* OverrideMe(Animal*) = 0;
};
struct Dog : Aniaml {
Dog* OverrideMe(Organism*) override { ... }
↑↑↑ ↑↑↑↑↑↑↑↑
covariant contravariant
};
Cela semble un peu inintéressant, mais cela a du sens. Si vous attendez un Animal*
, vous devriez être en mesure de gérer tout ce qui est un Animal*
(dont un Dog*
se qualifie). Inversement, si vous effectuez une opération sur un Animal*
, vous avez juste besoin d'une opération qui peut prendre un Animal*
- et une opération qui prend un Organism*
se qualifie sur ce front.
Notez que si l'entrée était co variante, cela casserait le système de type. Considérez quelque chose comme:
Animal* a = new Dog;
a->OverrideMe(new Cat);
Si Dog::OverrideMe
ont été autorisés à prendre un Dog*
, ce serait l'échec - un Cat*
n'est pas un Dog*
! Il est donc permis de prendre un Animal*
... ou quelque chose de plus générique que cela (par exemple Organism*
), puisque tout cela fonctionne bien.
C++ ne pas un support pour contravariance en entrée, seulement covariance en sortie. Donc, vous pouvez écrire soit:
Dog* OverrideMe(Animal*) override { ... }
ou:
Animal* OverrideMe(Animal*) override { .... }
mais rien d'autre.
Bien que C++ ne le supporte pas, la contravariance nécessiterait un paramètre moins spécifique que 'Parent *', pas plus spécifique. Le fait est que vous pouvez utiliser 'Parent' et ne pas connaître' Child'. Passer un 'Parent * 'qui n'est pas un' Child * 'casserait des choses. – chris
Votre conception est erronée. Il devrait être 'Parent virtuel * OverrideMe (Child * func) = 0; (avec un avant à l'enfant). Pourtant, c'est moche. Vous pouvez faire en sorte que Parent et l'enfant dérivent d'un nœud (en évitant l'héritage de parent à enfant). –