Héritage multiple + mess de fonction virtuelle
J'ai un diamant à l'héritage multiple scénario comme celui-ci:
A
/ \
B C
\ /
D
La mère commune, Une, définit un virtuel de la fonction fn().
Est-il possible pour les deux B et C afin de définir fn()
?
Si c'est le cas, la prochaine question est, pouvez D accéder à la fois aux B et C du fn() sans ambiguïté? Je suis en supposant qu'il existe certains syntaxe de cette..
Et est-il possible D faire sans connaître plus précisément, qui sont B et C? B et C peuvent être remplacées par d'autres classes et je veux le code D être générique.
Ce que je suis en train de faire est de D en quelque sorte énumérer toutes les instances du fn() il a dans son ascendance. Est-ce possible dans certains autres moyens que les fonctions virtuelles?
source d'informationauteur shoosh
Vous devez vous connecter pour publier un commentaire.
Sauf si vous les remplacez
fn
de nouveau dansD
non, il n'est pas possible. Car il n'y a pas de finale overrider dans un D de l'objet: les DeuxC
etB
remplacerA::fn
. Vous avez plusieurs options:C::fn
ouB::fn
. Ensuite, celui qui remplacent toujoursA::fn
a la finale overrider.A::fn
aswell commefn
dansC
etB
.Par exemple les résultats suivants dans une erreur de compilation:
Vous pouvez, toutefois dériver non virtuelle à partir de A en C et B, mais alors vous n'avez pas de diamant de l'héritage de plus. C'est, chaque membre dans Un apparaît deux fois dans B et C parce que vous avez deux Une classe de base des sous-objets dans un D objet. Je vous recommande de repenser la conception. Essayez de supprimer le double des objets comme ça qui nécessitent l'héritage virtuel. Il est souvent la cause de ce genre de situations conflictuelles.
Un cas très similaire à cela, c'est quand vous voulez remplacer une fonction spécifique. Imaginez que vous avez une fonction virtuelle avec le même nom dans B et C (maintenant sans une base commune). Et dans D vous souhaitez remplacer chaque fonction, mais de donner un comportement différent pour chacun. Selon que vous appeler la fonction avec un B pointeur ou C pointeur, vous avez le comportement différent. L'Héritage Multiple de la Partie III par Herb Sutter explique une bonne façon de le faire. Il pourrait vous aider à vous décider sur votre conception.
Première question, oui, B et C peuvent définir
fn()
comme une fonction virtuelle.Deuxièmement, D peut bien sûr l'accès
B::fn()
etC::fn()
par l'aide de la portée de l'opérateur ::Troisième question: D doit au moins savoir de B et de C, puisque vous devez définir sur la liste d'héritage. Vous pouvez utiliser des modèles pour laisser les types B et C ouvert:
Sur le souhait automatiquement les énumérer tous fn() les fonctions de toutes les classes qui hérite D: je ne suis pas sûr si c'est possible sans avoir recours à la licence MPL. Au moins, vous pouvez étendre mon exemple ci-dessus avec les versions qui traitent de 3 et plus de paramètres de modèle, mais je pense qu'il y a une partie supérieure (interne par le compilateur)limite du nombre de classe de paramètres du modèle.
Il y a déjà plusieurs questions qui traitent de ce. Semble que nous sommes à court de questions à poser. Peut-être la boîte de recherche doit être plus grand que l'Poser une Question bouton.
Voir
Vous ne pouvez pas vous énumérer les définitions de fn() dans l'ascendance. C++ manque de réflexion. La seule façon que je peux imaginer est un géant de tests de boucle de la typeid de tous les ancêtres possibles. Et ça fait mal à l'imaginer.
Vous voudrez peut-être regarder à Loki TypeLists si vous avez vraiment besoin pour être en mesure de retracer les ancêtres et énumérer les types. Je ne suis pas sûr si ce que vous demandez est vraiment possible sans un tas de travail. Assurez-vous que vous n'êtes pas sur de génie ici.
Sur une note un peu différente, si vous allez utiliser, à MI de cette manière (c'est à dire, la redoutable diamant), vous devez être très explicite au sujet de qui virtuel membre que vous souhaitez. Je ne peux pas penser à une bonne cas où vous voulez choisir la sémantique de
B::fn()
surC::fn()
sans explicitement de prendre une décision lors de l'écriture deD
. Vous aurez probablement choisir l'un sur l'autre (ou même les deux) sur base de ce que la méthode individuelle. Une fois que vous avez pris une décision, la condition est que les changements héréditaires de ne pas modifier les attentes ou sémantique de l'interface.Si vous êtes vraiment inquiet à propos de la permutation dans une nouvelle classe, dire
E
à la place de direB
oùE
ne descend pas deB
mais offre la même interface, alors vous devriez vraiment utiliser le modèle de l'approche si je ne suis pas sûr de savoir pourquoi il y a unstatic_cast<>
là...fonctionne très bien et semble un peu plus facile à regarder.
Vividos a déjà répondu à la partie principale de la poste. Même si je voudrais utiliser le champ d'application de l'opérateur au lieu de les plus lourdes static_cast<> + de l'opérateur de déréférencement.
En fonction de la tâche à portée de main, peut-être vous pouvez modifier la relation d'héritage (de D à B et C pour les moins de couplage composition (plus éventuellement, l'héritage d'Un). C'est en supposant que vous n'avez pas besoin D être utilisé polimorphically que B ou C, et que vous n'avez pas vraiment besoin de B et C le partage de la même base instance.
Si vous optez pour la composition, vous pouvez recevoir le B et C comme arguments à votre constructeur comme références/pointeurs de type A, prise D ignorer complètement les types B et C. a ce stade, vous pouvez utiliser un conteneur pour que de nombreux objets dérivés. Votre propre mise en œuvre de la fn() (si vous le décidez) ou toute autre méthode.