C++ ne peut pas convertir à partir d'Une base de dérivés de type B, par l'entremise de base virtuelle d'Un
J'ai trois classes:
class A {};
class B : virtual public A {};
class C : virtual public A {};
class D: public B, public C {};
De tenter une statique de la fonte de A* B* j'obtiens l'erreur ci-dessous:
cannot convert from base A to derived type B via virtual base A
Vous devez vous connecter pour publier un commentaire.
Afin de comprendre le système des castes, vous avez besoin de plonger dans le modèle objet.
La représentation classique d'une hiérarchie simple modèle est de confinement: si
B
dérive deA
puis leB
objet, en effet, contenir uneA
sous-objet côtés de ses propres attributs.Avec ce modèle de passer est une simple manipulation du pointeur par un décalage connue au moment de la compilation, qui dépend de la disposition de la mémoire de
B
.C'est ce que static_cast n': une statique de la fonte est surnommé statique car le calcul de ce qui est nécessaire pour la fonte est faite à la compilation, soit de l'arithmétique des pointeurs ou des conversions (*).
Toutefois, lorsque
virtual
héritage des coups de pied dans, les choses ont tendance à devenir un peu plus difficile. Le principal problème est que, avecvirtual
l'héritage de toutes les sous-classes partagent la même instance de la sous-objet. Pour ce faire,B
va avoir un pointeur vers uneA
, au lieu d'uneA
propre, et leA
objet de classe de base sera instancié à l'extérieur deB
.Par conséquent, il est impossible au moment de la compilation pour être en mesure de déduire le nécessaire de l'arithmétique des pointeurs: il dépend de l'exécution type de l'objet.
Chaque fois qu'il y a un temps d'exécution type de dépendance, vous avez besoin de RTTI (RunTime Type d'Information), et l'utilisation de RTTI pour la contention est le travail de dynamic_cast.
En résumé:
static_cast
dynamic_cast
Les deux autres sont aussi au moment de la compilation de moulages, mais ils sont si spécifiques qu'il est facile de se rappeler ce qu'ils sont... et elles sont malodorantes, afin de mieux ne pas les utiliser du tout de toute façon.
(*) Comme le fait remarquer @curiousguy dans les commentaires, cela ne tient que pour passer. Un
static_cast
permet upcasting quel que soit virtuel ou de l'héritage simple, mais ensuite, le casting est également inutile.static_cast
peut être utilisé pour convertir un dérivé ptr pour une base virtuelle ptr.dynamic_cast
est possible uniquement pour les classes polymorphes:dynamic_cast
signifie "utilise le vptr" (dans la plupart des cas). D'une conversion à une classe de base virtuelle utilise le vptr ou un pointeur interne (ou un fixe de décalage lors de la finale complète type est connu).static_cast
fait de la fonte au moment de l'exécution. Sortie (sans expression cast) est également effectuée au moment de l'exécution. Même s'il est vrai, que le code compilé est plus courte que pourdynamic_cast
. Pour les pointeursstatic_cast
compile unif != nullptr
, puis ajoute un offset connu au moment de la compilation. Toutefois, si l'héritage virtuel est inclus,static_cast
et sortie compile également uneif != nullptr
, puis ajoute un offset connu au moment de l'exécution. Exemple.static_cast
pouvez également appeler ctors., ce qui est aussi tout moment de l'exécution.static_cast
peut faire beaucoup de chose. Je pensais que nous discutions ptr jette ici, non pas implicite conv en général, ou comment construire un obj. 2) Pouvons-nous accepter que le contexte est: faire de la même conversion de type X de type Y soit impl., w/ quelques casting oper ou d'une autre. 3) Pouvez-vous décrire X et Y tels que ces choix sont valables et donner diff code compilé?static_cast
serait toujours appliquer un fixe décalage constant. 3) Le choix de deux de conversion de X et de Y, U->V entre un "nouveau style" cast*_cast
, de style ancien en fonte, la conversion implicite pour les deux types U,V., auquel cas X et Y) à la fois valables b) différentes au mode de génération de code de niveau?Autant que je sache, vous devez utiliser
dynamic_cast
parce que l'héritage estvirtual
et vous êtes à la de passer.Vous ne pouvez pas utiliser
static_cast
dans cette situation, car le compilateur ne sait pas le décalage de B par rapport à Une au moment de la compilation. Le décalage doit être calculé au moment de l'exécution basé sur le type exact de la plupart des dérivés de l'objet. Par conséquent, vous devez utiliserdynamic_cast
.static_cast
.Oui, vous devez utiliser un dynamic_cast, mais vous aurez à faire la classe de base polymorphe, par exemple en ajoutant une virtuel dtor.
Selon la norme docs,
Section 5.2.9 - 9, pour Statique de la Fonte,
Par conséquent, il n'est pas possible et vous devez utiliser
dynamic_cast
...Dans votre code, vous tentez static_cast avec 'T = B*' et 'e = A*'
Maintenant 'B* t(A*)" n'est pas bien formé en C++ (mais 'A* t B*)' est parce que 'a' est Un virtuel sans ambiguïté et accessible à base de "B". Par conséquent, le code provoque une erreur.
Je ne sais pas si c'est "safe" mais.
En supposant
B dérivée à partir d'Une (et Une virtuelle pure)
Depuis que je SAIS qu'un pointeur vers B reste toujours un pointeur vers B.
ce programme s'exécute correctement et de retour d'impression "bonjour!" et la valeur de l'autre objet (dans ce cas "2").
par la voie, ce que je fais, c'est très dangereux (personnellement, je donne un ID différent pour chaque classe et j'affirme après réinterpréter le casting que le courant ID est égale à une autre pièce d'identité pour être sûr que nous faisons quelque chose avec 2 classes) et comme vous le voyez je me suis restreint à "const" méthodes. Ainsi, cela permettra de travailler avec des "non-const" méthodes, mais si vous faites quelque chose de mal à attraper le bug sera presque unpossible. Et même avec affirmation il y a 1 chance sur 4 milliards de réussir affirmation, même quand il est censé à l'échec
(assert(ID== autre->ID);)
Par la voie.. Un bon OO design ne doit pas exiger ce genre de choses, mais dans mon cas, j'ai essayé de refactor/re-conception du code, sans être en mesure de déposer l'utilisation de réinterpréter la coulée. de manière générale, vous POUVEZ éviter ce genre de choses.