Comment atteindre virtuel de la fonction de modèle” en C++
tout d'abord: j'ai lu et je sais maintenant qu'un modèle virtuel de la fonction membre n'est pas (encore?) possible en C++. Une solution consisterait à faire de la classe un modèle et utiliser le modèle argument des états-fonction.
Mais dans le contexte de la programmation orientée objet, je trouve que l'exemple ci-dessous ne serait pas très "naturel" si la classe était en fait un modèle. Veuillez noter que le code est en fait pas le travail, mais le gcc-4.3.4 rapports: error: templates may not be ‘virtual’
#include <iostream>
#include <vector>
class Animal {
public:
template< class AMOUNT >
virtual void eat( AMOUNT amount ) const {
std::cout << "I eat like a generic Animal." << std::endl;
}
virtual ~Animal() {
}
};
class Wolf : public Animal {
public:
template< class AMOUNT >
void eat( AMOUNT amount) const {
std::cout << "I eat like a wolf!" << std::endl;
}
virtual ~Wolf() {
}
};
class Fish : public Animal {
public:
template< class AMOUNT >
void eat( AMOUNT amount) const {
std::cout << "I eat like a fish!" << std::endl;
}
virtual ~Fish() {
}
};
class GoldFish : public Fish {
public:
template< class AMOUNT >
void eat( AMOUNT amount) const {
std::cout << "I eat like a goldfish!" << std::endl;
}
virtual ~GoldFish() {
}
};
class OtherAnimal : public Animal {
virtual ~OtherAnimal() {
}
};
int main() {
std::vector<Animal*> animals;
animals.push_back(new Animal());
animals.push_back(new Wolf());
animals.push_back(new Fish());
animals.push_back(new GoldFish());
animals.push_back(new OtherAnimal());
for (std::vector<Animal*>::const_iterator it = animals.begin(); it != animals.end(); ++it) {
(*it)->eat();
delete *it;
}
return 0;
}
Donc la création d'un "Fish< Montant > foo" est une sorte d'étrange. Cependant, il me semble souhaitable de fournir une quantité arbitraire de nourriture à manger pour chaque animal.
Donc, je suis à la recherche d'une solution sur la façon d'obtenir quelque chose comme
Fish bar;
bar.eat( SomeAmount food );
Cela devient particulièrement utile lorsque l'on regarde la boucle for. On peut, comme pour nourrir une quantité spécifique (FoodAmount) pour tous les différents animaux (via manger() et bind1st() par exemple), il n'a pas pu être fait facilement, bien que je me suis retrouvé trouve cela très inuitive (et donc dans une certaine mesure "naturelles). Alors que certains pourraient veux dire maintenant que cela est dû à la "uniforme"-caractère d'un vecteur, je pense/espère qu'il devrait être possible d'atteindre cet objectif et je voudrais vraiment savoir comment, que c'est étonnant de moi pendant un certain temps maintenant...
[MODIFIER]
Peut-être de clarifier la motivation derrière ma question, je veux programmer un Exportateur de classe et de laisser différente, plus des classes spécialisées en découlent. Tandis que le haut-niveau de l'Exportateur de la classe est généralement uniquement pour les cosmétiques/structurelle but, un GraphExporter-classe est dérivée, qui doit encore servir de classe de base pour encore plus de specialzed à l'exportation. Cependant, à l'instar de l'Animal-exemple, je voudrais être en mesure de définir GraphExporter* même spécialisés/classes dérivées (par exemple sur SpecialGraphExplorer) mais lors de l'appel d'écriture "( out_file )", il doit appeler les fonction de membre pour SpecialGraphExporter au lieu de GraphExporter::write( out_file).
Peut-être ce qui a fait de ma situation et des intentions claires.
Mieux,
Ombre
- Ce n'
fish.eat("string")
faire? Ce n'wolf.eat(Fish())
faire? Pouvez-vous utiliser une classe de base abstraiteAmount
au lieu d'essayer d'en faire un paramètre de modèle? Amount
sonne beaucoup comme une valeur, plutôt que d'un type, qui me rend très confus au sujet de pourquoi vous vous sentez un modèle est nécessaire ici.- Puis-je vous demander pourquoi voulez-vous décrire une quantité en tant que classe? Il me semble que la quantité type peut bien être connue au moment de la compilation, c'est à dire
size_t
. Qu'ainsi vous permettra de passer des valeurs différentes. Ou peut-être un autre exemple peut démontrer la nécessité de mieux. - Ce n'est pas MS spécifique, ils sont en utilisant une ancienne version de gcc. Si vous voulez jouer avec de nouvelles fonctionnalités de C++ en particulier quelques chouettes choses à partir de C++0x vous devez être sur la plus récente de gcc 4.6+ ou MSVC 10+
- J'utilise ici juste pour des fins d'illustration. On pourrait penser à cela comme une unité (kg, tonne...).
- J'ai lu votre question à plusieurs reprises et je ne peux toujours pas comprendre ce que vous essayez d'accomplir avec l'basées sur des modèles de fonction qui n'a pas pu être résolu avec une classe qui stocke de poids (ou de masse) et permet la conversion vers/à partir de différentes unités.
- Si vous souhaitez utiliser des unités, vous devriez jeter un coup d'oeil à boost::unités (boost.org/doc/libs/1_46_1/doc/html/boost_units.html)
- En général, ces unités ne sont pas exprimées comme des types uniques, mais comme un seul type qui construit le facteur d'échelle en elle. Vous pouvez paramétrer le type d'aliments, tels qu'un loup peut manger une livre de poisson tandis que l'ours peut manger une tonne de chair humaine, mais ce ne serait pas un cas pour les modèles, en particulier dans la classe de base. manger n'est plus une fonction commune à tous les animaux.
- Malheureusement, l'exemple n'a pas de servir jusqu'à ce que le bien que j'ai déjà pensé qu'il serait... La question n'était pas sur la réalisation d'une unité de fonctionnalités, ou une telle. Il est/était destiné à refléter mon point de vue sur un lieu "naturel", par exemple, que chaque animal doit manger. Et je cherchais une interface pratique à réaliser quelque chose de similaire avec un Exportateur de classe.
- Hey Hey - j'ai trouvé une mise en œuvre réelle que vous pouvez être en mesure d'utiliser
- Dans ce d'autres StackOverflow question, un utilisateur mentionné le "type d'effacement de" technique", vous pourriez être intéressé à regarder.
- pour semble être le seul à comprendre la question plutôt que de discuter de la validité du jouet en exemple...
Vous devez vous connecter pour publier un commentaire.
Après réflexion, j'ai reconnu ce que la classique multi-méthode exigence, c'est à dire une méthode qui distribue basé sur la runtime type de plus d'un paramètre. D'habitude fonctions virtuelles sont
single dispatch
en comparaison (et ils acheminent sur le type dethis
seulement).Consulter les documents suivants:
Ici est le "simple" approche à partir de l'article de wikipédia pour référence (le moins simple approche des échelles de mieux pour un plus grand nombre de types dérivés):
Évidemment, fonction membre virtuelle modèles ne sont pas autorisés et ne pouvait pas être réalisé même en théorie. Pour construire une classe de base virtuelle de la table, il doit y avoir un nombre fini de fonction virtuelle-pointeur entrées. Un modèle de fonction serait admettre une quantité indéfinie de "surcharges" (c'est à dire les instanciations).
Théoriquement parlant, une langue (comme C++) pourrait permettre une fonction membre virtuelle des modèles si elle avait un mécanisme pour spécifier la (fini) liste des instanciations. C++ n'ont que le mécanisme (soit explicite modèle instanciations), donc je suppose qu'il pourrait être possible de le faire dans une nouvelle norme C++ (bien que je n'ai aucune idée de ce qu'elle impliquerait pour le compilateur fournisseurs pour mettre en œuvre cette fonctionnalité). Mais, c'est juste une discussion théorique, dans la pratique, ce n'est tout simplement pas permis. Le fait demeure, vous avez à faire le nombre de fonctions virtuelles finis (pas de modèles de permis).
Bien sûr, cela ne signifie pas que le modèle de classe ne peut pas avoir les fonctions virtuelles, cela ne signifie pas que les fonctions virtuelles ne peuvent pas appeler les modèles de fonction. Donc, il ya beaucoup de solutions dans cette veine (comme le modèle Visiteur ou d'autres systèmes).
Une solution qui, je pense, sert votre but (même si c'est difficile à comprendre) élégamment est le suivant (qui est essentiellement un modèle visiteur):
Ci-dessus est une super solution, car il permet de définir un nombre fini de surcharges que vous voulez dans un seul endroit (dans le Eater_impl modèle de classe) et tous vous avez besoin dans la classe dérivée est une fonction de modèle (et éventuellement d'autres surcharges, pour des cas particuliers). Il y a, bien sûr, un peu de surcharge, mais je suppose qu'un peu plus de réflexion pourrait être mis en elle afin de réduire les frais généraux (supplémentaire de stockage de référence et l'allocation dynamique de Eater_impl). Je suppose que, l'curieusement récurrents de modèle de modèle pourrait probablement être employé en quelque sorte à cette fin.
derived()
méthode dans la mise en œuvre de la classe qui gère le casting. En outre, j'ai étendu le modèle pour gérer la mise en œuvre de plusieurs générations (par exemple,Animal
->Canine
->{Wolf, Dog}
).Je pense que le modèle visiteur peut être une solution.
Mise à JOUR
J'ai fini mon exemple:
cette affiche:
Par Mikael post, j'ai fait une autre branche, à l'aide de la PFI et suivants Propre style à l'aide de
derived()
expresse de la sous-classe de référence:De sortie:
Cet extrait peut être trouvé dans le code source ici: repro:c808ef0:cpp_quick/virtual_template.cc
Virtuel fonction de modèle n'est pas autorisé. Cependant, vous pouvez utiliser l'un OU l'autre ici.
Vous pourriez faire une interface à l'aide de méthodes virtuelles et de mettre en œuvre vos animaux divers en termes d'avoir une alimentation interface. (c'est à dire PIMPL)
Moins intuitive de l'homme serait d'avoir un non-membre non-ami modèle de fonction comme une fonction libre qui pourrait prendre basées sur des modèles de const référence à tout animal et de les faire manger en conséquence.
Pour l'enregistrement, vous n'avez pas besoin de modèles ici. Virtuelle Pure méthode abstraite sur la classe de base est assez à la force et à l'interface où tous les animaux doivent manger et de définir la façon dont ils le font avec un remplacement, en fournissant régulièrement virtuel suffirait de dire que tous les animaux peuvent manger, mais si ils n'ont pas une manière spécifique, il peut utiliser cette méthode par défaut.
Vous pouvez créer un modèle de classe avec fonction virtuelle, et de mettre en œuvre la fonction dans la classe dérivée sans utiliser de modèle dans le follwing façon:
malheureusement je havn'pas trouvé un moyen de créer une fonction virtuelle avec les paramètres de modèle sans déclaration de la classe en tant que modèle et il type de modèle sur le dervied classe
J'ai copié ton code et l'a modifié, de sorte que maintenant, il doit travailler exactement comme vous le souhaitez:
~Fish() override = default;
au lieuEn vous scénario, vous êtes essayer de mélanger le moment de la compilation, le polymorphisme polymorphisme d'exécution, mais il ne peut pas être fait dans ce "direction".
Essentiel, le MONTANT de votre argument de modèle représente une interface attendue pour le type de mettre en œuvre basée sur l'union de toutes les opérations de mise en œuvre de manger les utilisations. Si vous créez un type abstrait, qui avait déclaré que chacune de ces opérations en les rendant virtuel en cas de besoin, vous pouvez ensuite appeler manger avec différents types (qui a été dérivée à partir de votre MONTANT de l'interface). Et il allait se comporter comme prévu.
Je ne travaille pas avec des modèles, mais je pense que:
(1) Vous ne pouvez pas utiliser des modèles à l'intérieur d'une classe, les modèles sont plus comme des types ou des variables globales.
(2) En O. O. P., le même problème que vous, et que vous essayez de résoudre à l'aide de modèles, peut être résolu par l'utilisation de l'héritage.
Classes fonctionnent comme des modèles, vous pouvez ajouter de nouvelles choses, ou de remplacer les choses de classes avec des pointeurs, pointeurs vers des objets (A. K. A. "références") et en remplaçant les fonctions virtuelles.
Acclamations.
override
finit par un mot-clé dans 0x; il peut être répertorié un attribut, mais ceux-là ne sont pas utilisées de la façon dont vous l'avez ici.