J'ai entendu dire que les modèles de fonction de membre de classe C ++ ne peuvent pas être virtuels. Est-ce vrai?
S'ils peuvent être virtuels, quel est un exemple de scénario dans lequel on utiliserait une telle fonction?
c++
templates
virtual-functions
function-templates
c++-faq
WannaBeGeek
la source
la source
Réponses:
Les modèles sont tous sur le compilateur générant du code au moment de la compilation . Les fonctions virtuelles concernent le système d'exécution qui détermine la fonction à appeler lors de l' exécution .
Une fois que le système d'exécution a compris qu'il aurait besoin d'appeler une fonction virtuelle modélisée, la compilation est terminée et le compilateur ne peut plus générer l'instance appropriée. Par conséquent, vous ne pouvez pas avoir de modèles de fonction de membre virtuel.
Cependant, il existe quelques techniques puissantes et intéressantes issues de la combinaison du polymorphisme et des modèles, notamment ce que l'on appelle l' effacement de type .
la source
Virtual functions are all about the run-time system figuring out which function to call at run-time
- désolé mais c'est une façon plutôt fausse de le faire, et assez déroutant. C'est juste une indirection, et il n'y a pas de "calcul de l'exécution" impliqué, il est connu pendant la compilation que la fonction à appeler est celle pointée par le n-ième pointeur de la table. "Comprendre" implique qu'il existe des vérifications de type et autres, ce qui n'est pas le cas.Once the run-time system figured out it would need to call a templatized virtual function
- si la fonction est virtuelle ou non est connue au moment de la compilation.void f(concr_base& cb, virt_base& vb) { cb.f(); vb.f(); }
, alors il "sait" pour quelle fonction est invoquée au pointcb.f()
appelé et ne le sait pas pourvb.f()
. Ce dernier doit être découvert lors de l'exécution , par le système d'exécution . Que vous vouliez appeler cela "comprendre", et que ce soit plus ou moins efficace, cela ne change pas un peu ces faits.À partir de modèles C ++ Le guide complet:
la source
C ++ n'autorise pas actuellement les fonctions de membre de modèle virtuel. La raison la plus probable est la complexité de sa mise en œuvre. Rajendra donne une bonne raison pour laquelle cela ne peut pas être fait en ce moment, mais cela pourrait être possible avec des changements raisonnables de la norme. Il est particulièrement difficile de déterminer le nombre d'instanciations d'une fonction basée sur un modèle et de créer la table virtuelle si vous considérez la place de l'appel de fonction virtuelle. Les normalisateurs ont juste beaucoup d'autres choses à faire en ce moment et C ++ 1x est aussi beaucoup de travail pour les rédacteurs du compilateur.
Quand auriez-vous besoin d'une fonction membre basée sur des modèles? J'ai rencontré une fois une telle situation où j'ai essayé de refaçonner une hiérarchie avec une classe de base virtuelle pure. C'était un style médiocre pour mettre en œuvre différentes stratégies. Je voulais changer l'argument de l'une des fonctions virtuelles en un type numérique et au lieu de surcharger la fonction membre et de remplacer chaque surcharge dans toutes les sous-classes, j'ai essayé d'utiliser des fonctions de modèle virtuel (et j'ai dû découvrir qu'elles n'existent pas .)
la source
Tables de fonctions virtuelles
Commençons par quelques informations sur les tables de fonctions virtuelles et leur fonctionnement ( source ):
Mon problème ou comment je suis venu ici
J'essaie d'utiliser quelque chose comme ça maintenant pour une classe de base de fichiers cubiques avec des fonctions de chargement optimisées basées sur des modèles qui seront implémentées différemment pour différents types de cubes (certains stockés par pixel, certains par image, etc.).
Du code:
Ce que j'aimerais que ce soit, mais il ne se compilera pas en raison d'un combo basé sur un modèle virtuel:
J'ai fini par déplacer la déclaration de modèle au niveau de la classe. Cette solution aurait obligé les programmes à connaître les types spécifiques de données qu'ils liraient avant de les lire, ce qui est inacceptable.Solution
avertissement, ce n'est pas très joli mais cela m'a permis de supprimer le code d'exécution répétitive
1) dans la classe de base
2) et dans les classes enfants
Notez que LoadAnyCube n'est pas déclaré dans la classe de base.
Voici une autre réponse de dépassement de pile avec une solution: besoin d'une solution de contournement de membre de modèle virtuel .
la source
Le code suivant peut être compilé et s'exécute correctement, à l'aide de MinGW G ++ 3.4.5 sur Windows 7:
et la sortie est:
Et plus tard, j'ai ajouté une nouvelle classe X:
Quand j'ai essayé d'utiliser la classe X dans main () comme ceci:
g ++ signale l'erreur suivante:
Il est donc évident que:
la source
Non, ils ne peuvent pas. Mais:
a le même effet si tout ce que vous voulez faire est d'avoir une interface commune et de reporter l'implémentation aux sous-classes.
la source
Foo
pointeur est qualifié deFoo<Bar>
, il ne peut pas pointer vers unFoo<Barf>
ouFoo<XXX>
.Non, les fonctions membres du modèle ne peuvent pas être virtuelles.
la source
Dans les autres réponses, la fonction de modèle proposée est une façade et n'offre aucun avantage pratique.
Le langage ne permet pas les fonctions de modèle virtuel mais avec une solution de contournement, il est possible d'avoir les deux, par exemple une implémentation de modèle pour chaque classe et une interface commune virtuelle.
Il est cependant nécessaire de définir pour chaque combinaison de type de modèle une fonction de wrapper virtuel factice:
Production:
Essayez-le ici
la source
Pour répondre à la deuxième partie de la question:
Ce n'est pas une chose déraisonnable de vouloir faire. Par exemple, Java (où chaque méthode est virtuelle) n'a aucun problème avec les méthodes génériques.
Un exemple en C ++ de vouloir un modèle de fonction virtuelle est une fonction membre qui accepte un itérateur générique. Ou une fonction membre qui accepte un objet fonction générique.
La solution à ce problème est d'utiliser l'effacement de type avec boost :: any_range et boost :: function, qui vous permettra d'accepter un itérateur ou un foncteur générique sans avoir besoin de faire de votre fonction un modèle.
la source
Il existe une solution de contournement pour la «méthode de modèle virtuel» si un ensemble de types pour la méthode de modèle est connu à l'avance.
Pour montrer l'idée, dans l'exemple ci-dessous, seuls deux types sont utilisés (
int
etdouble
).Là, une méthode de modèle «virtuelle» (
Base::Method
) appelle la méthode virtuelle correspondante (l'une d'entre ellesBase::VMethod
) qui, à son tour, appelle l'implémentation de la méthode de modèle (Impl::TMethod
).Il suffit d'implémenter la méthode du modèle
TMethod
dans les implémentations dérivées (AImpl
,BImpl
) et d'utiliserDerived<*Impl>
.Production:
NB:
Base::Method
est en fait excédentaire pour le code réel (VMethod
peut être rendu public et utilisé directement). Je l'ai ajouté pour qu'il ressemble à une méthode de modèle «virtuelle» réelle.la source
Base
classe d' origine chaque fois que vous devez appeler une fonction de modèle avec un type d'argument non compatible avec ceux mis en œuvre jusqu'à présent. Éviter cette nécessité est l'intention des modèles ...Bien qu'une question plus ancienne à laquelle beaucoup ont répondu, je pense qu'une méthode succincte, pas si différente des autres publiées, consiste à utiliser une macro mineure pour faciliter la duplication des déclarations de classe.
Alors maintenant, pour implémenter notre sous-classe:
L'avantage ici est que, lors de l'ajout d'un type nouvellement pris en charge, tout peut être fait à partir de l'en-tête abstrait et renoncer éventuellement à le rectifier dans plusieurs fichiers source / en-tête.
la source
Au moins avec gcc 5.4, les fonctions virtuelles pourraient être des membres de modèle mais doivent être des modèles eux-mêmes.
Les sorties
la source
Essaye ça:
Écrivez dans classeder.h:
Vérifiez, si vous travaillez avec cela, d'écrire ce code dans main.cpp:
la source