En C++, la distinction importante est le temps d'exécution de vs au moment de la compilation de liaison. Ad-hoc vs paramétrique n'aide pas vraiment, comme je l'expliquerai plus tard.
|----------------------+--------------|
| Form | Resolved at |
|----------------------+--------------|
| function overloading | compile-time |
| operator overloading | compile-time |
| templates | compile-time |
| virtual methods | run-time |
|----------------------+--------------|
Remarque - polymorphisme de l'exécution peut encore être résolu à la compilation, mais c'est juste de l'optimisation. Avoir besoin d'un soutien au moment de l'exécution de la résolution de manière efficace, et en échange contre d'autres questions, fait partie de ce qui a conduit à des fonctions virtuelles étant ce qu'elles sont. Et c'est vraiment la clé pour toutes les formes de polymorphisme en C++ - chaque provient de différents ensembles de compromis faite dans un contexte différent.
Surcharge de fonctions et la surcharge d'opérateur sont la même chose dans tous les sens qui compte. Le nom et la syntaxe pour leur utilisation n'affecte pas le polymorphisme.
Les modèles vous permettent de spécifier les lots de la fonction des surcharges à la fois.
Il y a un autre ensemble de noms pour la même résolution, le temps d'idée...
|---------------+--------------|
| early binding | compile-time |
| late binding | run-time |
|---------------+--------------|
Ces noms ne sont plus associés à la programmation orientée objet, donc c'est un peu bizarre de dire qu'un modèle ou d'autres non-membre de la fonction utilise la liaison anticipée.
Pour mieux comprendre la relation entre les fonctions virtuelles et de surcharge de fonctions, il est également utile de comprendre la différence entre "envoi" et "multiple dispatch". L'idée peut être comprise comme une progression...
- Tout d'abord, il y a monomorphe fonctions. La mise en œuvre de la fonction est identifiée de manière unique par le nom de la fonction. Aucun des paramètres spéciaux.
- Ensuite, il existe une seule expédition. L'un des paramètres est considéré comme spécial, et utilisé (avec le nom) pour identifier la mise en œuvre d'utilisation. En programmation orientée objet, nous avons tendance à penser de ce paramètre comme "l'objet", la liste avant le nom de la fonction, etc.
- Ensuite, il y a de multiples expédition. Tous les paramètres de contribuer à l'identification de l'implémentation à utiliser. Donc, une fois de plus, aucun des paramètres doit être spécial.
Il y a évidemment plus de la programmation orientée objet que d'une excuse pour désigner un paramètre spécial, mais c'est une partie de lui. Et concernant ce que je disais à propos de compromis,- envoi qui est assez facile à faire efficacement (l'habitude de la mise en œuvre est appelée "tables virtuelles"). La répartition Multiple est plus maladroit, et pas seulement en termes d'efficacité, mais aussi pour la compilation séparée. Si vous êtes curieux, vous pouvez rechercher ", l'expression "problème".
Tout comme il est un peu étrange d'utiliser le terme "liaison anticipée" pour les non-membres fonctions, c'est un peu étrange d'utiliser les termes "envoi" et "multiple dispatch" où le polymorphisme est résolu au moment de la compilation. Habituellement, C++ est considérée comme n'ayant pas la répartition multiple, qui est considéré comme un type particulier de l'exécution de la résolution. Cependant, la fonction de surcharge peut être vu comme multiple à répartition effectuée au moment de la compilation.
Pour en revenir à paramétrique vs ad-hoc polymorphisme, ces termes sont de plus en plus populaire dans la programmation fonctionnelle, et ils n'ont pas assez de travail en C++. Même si...
Polymorphisme paramétrique signifie que vous avez les types de paramètres, et exactement le même code est utilisé quel que soit le type que vous utilisez pour ces paramètres.
Ad-hoc polymorphisme ad-hoc dans le sens que vous fournir un code différent selon les types.
Les surcharges et les fonctions virtuelles sont deux exemples d'ad-hoc polymorphisme.
Encore une fois, il y a quelques synonymes...
|------------+---------------|
| parametric | unconstrained |
| ad-hoc | constrained |
|------------+---------------|
Sauf que ce ne sont pas tout à fait synonymes, mais ils sont généralement traitées comme si elles étaient, et c'est là que la confusion est susceptible de se produire en C++.
Le raisonnement derrière traiter ces comme synonymes est qu'en restreignant le polymorphisme particulier les classes de types, il devient possible d'utiliser des opérations spécifiques à ces classes de types. Le mot "classes" ici peuvent être interprétés dans le sens de la programmation orientée objet, mais vraiment juste fait référence (généralement le nom) les ensembles de types qui partagent certaines opérations.
Afin de polymorphisme paramétrique est généralement pris (au moins par défaut) pour impliquer sans contrainte polymorphisme. Parce que le même code est utilisé quel que soit le type de paramètres, la seule supportable opérations sont ceux qui fonctionnent pour tous les types. En laissant l'ensemble des types sans contrainte, vous limiter sévèrement l'ensemble des opérations que vous pouvez appliquer à ces types.
En Haskell par exemple, vous pouvez avoir...
myfunc1 :: Bool -> a -> a -> a
myfunc1 c x y = if c then x else y
L' a
ici est une contrainte de type polymorphe. Il pourrait être n'importe quoi, donc il n'y a pas beaucoup que nous pouvons faire avec les valeurs de ce type.
myfunc2 :: Num a => a -> a
myfunc2 x = x + 3
Ici, a
est contraint d'être un membre de l' Num
classe - types qui agissent comme des numéros. Cette contrainte permet de faire le numéro-ish choses avec ces valeurs, telles que ajouter. Même l' 3
est polymorphe - l'inférence de type chiffres que vous voulez dire que l' 3
de type a
.
Je pense à cela comme une contrainte polymorphisme paramétrique. Il n'y a qu'une mise en œuvre, mais elle ne peut être appliquée dans la limité de cas. Le ad-hoc aspect est le choix de la +
et 3
à utiliser. Chaque "instance" d' Num
a c'est propre, distincte de la mise en œuvre de ces. Donc, même en Haskell "paramétrique" et "sans contrainte" ne sont pas vraiment synonymes - ne me blâmez pas, c'est pas de ma faute!
En C++, à la fois les surcharges et les fonctions virtuelles sont ad-hoc polymorphisme. La définition de l'ad-hoc polymorphisme ne se soucie pas de savoir si la mise en œuvre est sélectionnée au moment de l'exécution ou au moment de la compilation.
C++ est très proche de polymorphisme paramétrique avec des modèles si chaque paramètre du modèle est de type typename
. Il y a des paramètres de type, et il y a un unique de mise en œuvre n'importe quels types sont utilisés. Cependant, la Substitution "l'Échec n'Est Pas Une Erreur" la règle signifie que les contraintes implicites résulter de l'utilisation des opérations dans le modèle. Des complications supplémentaires comprennent la spécialisation de modèle pour fournir une alternative aux modèles différents (ad-hoc), les implémentations.
Donc dans un sens C++ a du polymorphisme paramétrique, mais il est implicitement limité et pourrait être remplacée par une ad-hoc, des solutions de rechange - c'est à dire cette classification ne fonctionne pas vraiment pour le C++.