Tout, cela semble être un problème simple mais ça me donne des crises. Disons que j'ai une classe de base C++ appelée Animal et des classes dérivées Cat, Chien, Cheval, Hippopotame, Serpent. J'ai une autre classe appelée Zoo qui contient une liste (Qt List dans ce cas où la classe de base Animal est un QObject) d'objets Animal. Maintenant, ce que je veux faire est de créer un objet Zoo et être capable de le copier dans un autre objet Zoo et de faire en sorte que le Zoo de destination possède sa propre copie des Animaux. Le problème est dans le constructeur de copie de zoo parce qu'il pense qu'il a une liste d'animaux qu'il appelle le constructeur de copie pour l'animal au lieu de chien, chat, etc. car les compilateurs devraient faire. Pour contourner cela, j'ai changé la liste des animaux en une liste de pointeurs d'animaux, puis j'ai créé mon propre constructeur de copie d'animaux et un opérateur d'affectation. Chacun d'eux appelle la méthode Animal :: Clone (Animal & rhs) qui à son tour appelle chaque classe dérivée de la méthode Animals Clone() qui renvoie un nouveau pointeur alloué à partir du tas avec une copie de ses données. Tout fonctionne bien mais je continue à penser qu'il me manque une solution plus élégante. Donc ma question est, quand vous avez un conteneur avec des objets d'un type, comment pouvons-nous copier la classe qui contient le conteneur? J'espère que cela à du sens.Copie conteneur d'éléments avec héritage
Répondre
Ce que vous avez fait est presque la façon idiomatique de le faire en C++. La méthode virtuelle clone()
est en fait connue sous le nom de constructeur de copie virtuelle idiom. En général, vous le déclarez comme une méthode abstraite virtuelle de la signature suivante.
Animal * clone() const = 0;
Notez qu'il ne prend pas un paramètre rhs
, il retourne simplement un clone de lui-même. Étant donné un exemple d'un animal Animal * myPet
, vous pouvez obtenir une copie d'un en disant
Animal * mySecondPet = myPet->clone();
Vous êtes obligé de le mettre en œuvre dans les classes dérivées si elles doivent être instancié.
[Ed:] Comme vous l'avez découvert, il est impossible pour une classe de conteneur pour contenir les éléments directement et non pas par des pointeurs, en raison de la inhérente slicing problem dans la conception de C++.
En C++, votre solution est un idiome: elle est aussi élégante que possible, et tous ceux qui la voient, qui connaissent leur C++, doivent immédiatement savoir ce que vous voulez dire. Idiomes et certains modèles de conception font partie de la langue. Vous ne pouvez pas vous appeler compétent dans une langue, qu'elle soit humaine ou programmée, sans connaître les idiomes.
Dans plusieurs de mes projets, j'utilise une classe d'interface (toutes les méthodes virtuelles abstraites), appelée Cloneable
, qui consiste uniquement en cette méthode de clonage. Il est alors facile de forcer une classe de base à être clonable: il suffit d'hériter de Cloneable. Je souhaite que QEvent
était Cloneable
de cette façon, par exemple. En l'état, il est impossible de dupliquer QEvents
pour les publier dans plusieurs files d'attente d'événements.
La suggestion de Daniel "Avez-vous essayé de faire le constructeur de copie pour Animal virtuel?" ne peut pas être pris à la lettre. Il n'existe pas de constructeur de copie virtuelle ou de constructeur en C++ pour une raison simple: avant la construction d'un objet, sa table de méthode virtuelle n'est pas finalisée. Plus précisément, le code du constructeur d'Animal s'exécutera avant que les constructeurs des classes dérivées ne soient appelés pour échanger le pointeur de la table de méthode virtuelle avec celui de la classe dérivée. Ainsi, si vous avez effectué des appels de méthode virtuelle dans le constructeur, ils ne vont pas à une classe dérivée de votre classe. C'est tout.
Cela a du sens. Et puis dans la classe Zoo, implémentez le constructeur de copie et l'opérateur d'affectation pour parcourir la liste QList appelant la méthode clone() de chaque animal, n'est-ce pas? – Brad
C'est correct. –
- 1. Héritage de constructeur de copie
- 2. copie pixels SDL_Surface dans un conteneur STL
- 3. Héritage et suppression de constructeurs de copie et de déplacement
- 4. Caractéristiques du ressort avec héritage
- 5. C++ OOP Programme question sur le constructeur de copie? Héritage
- 6. javascript prototype héritage bug
- 7. Héritage multiple avec QThread et QWidget (héritage multiple avec QObject)
- 8. Copie d'objets d'erreur lorsque la classe contient boost :: :: conteneur flat_set
- 9. Héritage JPA avec PostgreSQL
- 10. Héritage avec génériques
- 11. héritage Trivial avec JavaScript
- 12. Composition avec héritage?
- 13. Génériques avec héritage
- 14. Héritage Mysql avec tables
- 15. Héritage avec Hibernate
- 16. héritage avec « objet » Scala
- 17. DataContract avec héritage?
- 18. Confus avec C++ Héritage
- 19. héritage avec Google Closure
- 20. Motif Builder avec héritage
- 21. héritage avec coffeescript
- 22. bisonC++ héritage avec polymorphique
- 23. héritage avec fluidité nhibernate
- 24. héritage (travail avec Collection.Generic)
- 25. Héritage multiple avec Django
- 26. Héritage avec incrémentation automatique
- 27. héritage simple avec mvc
- 28. Héritage profond avec JavaScript?
- 29. Multithreading avec héritage (C++)
- 30. Comment éliminer une copie de variable dans la classe de base avec héritage multiple?
Avez-vous essayé de rendre le constructeur de copie pour 'Animal' virtuel? – Daniel
Je suis d'accord avec Daniel, le seul moyen de surcharger une fonction de la classe parente pour que la fonction soit une fonction virtuelle, sinon le code est généré dans le compilateur. –
Le problème survient lorsque Animal hérite de QObject. Si je comprends bien, Qt interdit les copies d'objets qui héritent de QObject. Est-ce que quelqu'un sait si c'est correct? – Brad