Quels sont les modèles de problèmes typiques qui bénéficient d'un code conçu pour faire un usage intensif de l'héritage multiple?
Ce n'est qu'un exemple, mais celui que je trouve inestimable pour améliorer la sécurité et atténuer les tentations d'appliquer des changements en cascade à travers les appelants ou les sous-classes.
Là où j'ai trouvé l'héritage multiple incroyablement utile, même pour les interfaces sans état les plus abstraites, c'est l'idiome d'interface non virtuelle (NVI) en C ++.
Ce ne sont même pas vraiment des classes de base abstraites autant que des interfaces qui ont juste un peu d'implémentation pour appliquer les aspects universels de leurs contrats, car elles ne réduisent pas vraiment la généralité du contrat autant qu'elles le font mieux. .
Exemple simple (certains pourraient vérifier qu'un descripteur de fichier transmis est ouvert ou quelque chose comme ça):
// Non-virtual interface (public methods are nonvirtual/final).
// Since these are modeling the concept of "interface", not ABC,
// multiple will often be inherited ("implemented") by a subclass.
class SomeInterface
{
public:
// Pre: x should always be greater than or equal to zero.
void f(int x) /*final*/
{
// Make sure x is actually greater than or equal to zero
// to meet the necessary pre-conditions of this function.
assert(x >= 0);
// Call the overridden function in the subtype.
f_impl(x);
}
protected:
// Overridden by a boatload of subtypes which implement
// this non-virtual interface.
virtual void f_impl(int x) = 0;
};
Dans ce cas, peut f
- être est appelé par mille endroits dans la base de code, tandis quef_impl
est remplacé par une centaine de sous-classes.
Il serait difficile de faire ce genre de contrôle de sécurité dans les 1000 lieux qui appellent f
ou dans les 100 lieuxf_impl
.
En ne faisant que ce point d'entrée à la fonctionnalité non virtuelle, cela me donne un endroit central pour effectuer cette vérification. Et cette vérification ne réduit pas du tout l'abstraction, car elle affirme simplement une condition préalable requise pour appeler cette fonction. Dans un sens, cela renforce sans doute le contrat fourni par l'interface et soulage le fardeau de la vérification de l' x
entrée pour s'assurer qu'elle est conforme aux conditions préalables valides dans les 100 endroits qui la remplacent.
C'est quelque chose que je souhaite que chaque langage ait, et souhaite également, même en C ++, que ce soit un peu plus un concept natif (ex: ne pas nous obliger à définir une fonction distincte pour remplacer).
Ceci est extrêmement utile si vous ne l'avez pas fait assert
à l'avance et que vous vous en êtes rendu compte plus tard lorsque certains endroits aléatoires de la base de code rencontraient des valeurs négatives transmises f
.