Mon programme doit utiliser le vide * Afin de transporter des données ou des objets dans une situation d'invocation dynamique, de manière à pouvoir faire référence aux données des types arbitraires, même des types primitifs. Toutefois, j'ai récemment découvert que le processus de casting à basse-coiffe * en cas de classes avec plusieurs classes de base échoue et bloque même mon programme après avoir invoqué des méthodes sur ces pointeurs couplés, même si les adresses de mémoire semblent être correctes. L'accident arrive lors de l'accès à "Tablevis".
J'ai donc créé un petit cas de test, l'environnement est GCC 4.2 sur Mac OS X: P> produit la sortie suivante : P> Decorated (direct)30,30
Shape 30,30
Square 30,30
Decorated (per void*) 73952,73952
DecoratedSquare 30,30
3 Réponses :
Un statique_cast ou une dynamique_cast en présence de multiples héritage peut modifier la représentation du pointeur en le compensant de manière à désigner la bonne adresse. static_cast détermine le décalage correct en considérant des informations de saisie statiques. dynamic_cast le fait en cochant le type dynamique. Si vous allez jeter le vide *, vous perdez toutes les informations de saisie statiques et la possibilité d'obtenir des informations de saisie dynamiques, de sorte que le réinterpret_cast que vous utilisez est en supposant que le décalage est NULL, échouant parfois. P>
Cela signifie-t-il donc effectivement que le vide * ne sont pas réalisables dans de multiples situations de héritage?
Il est réalisable, tant que vous êtes toujours jeté sur le type réel de l'objet, pas une classe de base.
Voir mon commentaire sur la réponse de Mike
Plus précisément, vous devez lancer le vide * au type statique La valeur avait avant d'être lancée en annulation *.
Non seulement cela, un static_cast (code> ou une conversion implicite peut également utiliser des informations de type dynamique, en lisant le VPTR ou une autre alternative de mise en œuvre.
Ce n'est pas un bug de compilateur - c'est ce que convertir un pointeur sur celui-ci sur Vous devez obtenir les résultats corrects si vous reterpret_cast code> fait. L'objet code> décoratedsquare code> sera aménagé dans la mémoire quelque chose comme ceci:
Void * code> donnera à l'adresse du début de ces données, sans savoir quel type existe-t-il.
Reterpret_cast
décoré code> - mais le contenu de la mémoire réelle est le carré code>. Ceci est faux, vous obtenez donc un comportement indéfini. P>
Reterpret_cast > au type dynamique correct (c'est
décoratedsquare code>) , puis convertir en classe de base. p> p>
Qui l'explique, mais cela signifierait que sans connaissance de la sous-classe concrète, je ne peux pas produire de code qui fonctionne sur des pointeurs sur l'une des classes de base de manière polymorphe, comme il serait possible dans des situations d'héritage unique, où l'appelant n'a pas besoin connaître la sous-classe concrète. En d'autres termes, il ne serait pas possible de compiler un cadre et de l'utiliser plus tard lorsque les sous-classes concrètes sont connues? Cela signifie que de multiples héritage en C ++ n'est pas complet.
MI en C ++ est terminé, sauf si vous jetez les informations de type. Vous pouvez utiliser virtual code> fonctionner pour obtenir un comportement polymorphique sans connaître des sous-classes en béton si vous ne sortez pas sauvagement sur des types erronés.
Pour moi, comme je ne connais tout simplement pas le sous-type concret dans cette partie du cadre, cela signifie simplement que je ne peux pas utiliser de vide * là-bas. Je dois transporter des informations de type en quelque sorte en utilisant une "n'importe quel" ou similaire. Pas bien et pas ce que j'avais attendu :( Mais au moins tu m'as donné une bonne explication. Merci tout le monde
@Andre, ce n'est pas un problème de héritage multiple, c'est un problème de lancer des choses à annuler *. Ce qui fonctionne, je jette un pointeur à vide * puis de retour à son type d'origine statique i> (non dynamique comme Mike semble impliquer). Jeter un vide * à quelque chose d'autre est indéfini (Eh bien, il y a quelques exceptions près)
Vous pourrez peut-être faire ce que vous voulez avec un REINERPRET_CAST CODE> à
SHACE CODE> suivi d'un
dynamic_cast code> à
décoré code>. Je ne suis pas sûr à 100%, donc je ne l'ajouterai pas à la réponse. Il peut bien donner un comportement non défini.
Les modes naturels de construire un cadre utilisent des modèles ou des types abstraits. Void * est une façon de faire des trucs de niveau bas et ne doit pas être visible dans votre cadre.
@MIKE, Ici, le type statique original est décoréquare, de sorte que le vide * doit être coulé à la décoration desquels. Si le type statique original était de la forme *, le vide * doit être coulé à la forme * (et éventuellement, puis a été déposé de manière dynamique à décorarésquare).
Mike tu es mon héros! Pas ça marche: dynamic_cast
@Andre, êtes-vous sûr de ne pas pouvoir transporter des trucs autour de la forme * au lieu de vide *? Comme vous l'avez maintenant, bien que comment connaissez-vous un pointeur est une forme * et non INT * (ou autre type primitif)?
@quamrana je pouvais mais avec beaucoup plus d'effort, surtout que j'aurais besoin d'envelopper toutes les primitives avec des objets et de tout donner une classe de base commune. Cette partie-cadre est générée du code qui prend quelques vides * et les traduit en paramètres à un appel de méthode normal. De cette façon, je reçois une invocation de méthode dynamique, une caractéristique essentielle de mon cadre. Il ressemble beaucoup au concept de signal / machines à sous QT, ils utilisent les mêmes méthodes (nulk *) là-bas.
Répéter dix fois - la seule chose que vous pouvez faire en toute sécurité avec un Donc, si vous lancez un Vous dites que votre code accède à "types arbitraires, y compris types primitifs" via un vide *. Il n'y a rien de mal à cela - vraisemblablement qui reçoit les données sait à le traiter comme un Si quiconque reçoit seulement qu'il ne sait que pour le traiter comme une classe de base, telle que maintenant lorsque vous lancez REINERPRET_CAST CODE> Le pointeur est
Reterpret_cast CODE> Retour au même type de pointeur. Il en va de même avec les conversions sur
VOID * CODE>: Vous devez reconvertir le type d'origine.
décoratedsquare * code> à
Void * < / Code>, vous devez le jeter à
décoratedSquare * code>. Pas
décoré * code>, pas
carré * code>, pas
forme * code>. Certains d'entre eux pourraient travailler sur votre machine, mais il s'agit d'une combinaison de bonne chance et de comportement spécifique à la mise en œuvre. Cela fonctionne généralement avec une seule héritage, car il n'y a pas de raison évidente de mettre en œuvre des pointeurs d'objet d'une manière qui l'empêcherait de fonctionner, mais cela n'est pas garanti, et cela ne peut pas fonctionner en général pour une héritage multiple. P>
décoratedsquare * code> et non comme, dire,
int * code>. P>
décorée * code>, puis celui qui le convertit sur
vide * code> doit
static_cast code> La classe de base d'abord, puis à
Void * code>: p>
décorated_vp code> retour à
décorée * code>, vous obtiendrez le résultat de
static_cast
Steve merci pour cela. Je suppose beaucoup ça. En effet, il est toujours assuré que, dans la partie appelante du framework, il existe un type de pointeur de base connu qui est lancé à vide * puis transporté à l'extrémité de réception, qui connaît 2 choses: la classe de base la plus haute et une sous-classe où une méthode est défini. Il ne sait cependant pas la sous-classe concrète. Mais cela semble être correct maintenant, car l'extrémité réceptrice toujours réinterpret_casts à la même classe de base la plus haute que l'extrémité d'envoi a fait, puis une dynamique_cast ou statique_cast à la sous-classe intermédiaire où elle invoque la méthode souhaitée.
+1 pour "La seule chose que vous pouvez faire en toute sécurité avec un pointeur de réinterpret_cast est réinterpret_cast le revenant au même type de pointeur." Résume très bien la situation.
Vous ne pouvez utiliser que REINTERPRET_CAST à lancer à Void *, puis revenez au type d'origine. Vous pouvez PAS B> CASSER à NOID * et puis à autre chose.
Vous seriez beaucoup mieux à utiliser le motif de décorateur que MI, pas que cela résoudrait la coulée du problème vidimal *.