J'ai une arborescence de classe qui ressemble à ça (Pour ceux qui
connaissent, c'est un signal SystemC) :
If
^
|
A<T> B
^ ^
| |
`--.--'
|
C<T>
(If est une interface)
J'ai un pointeur ptr sur un objet de type B, mais le type du pointeur
est If *. Je veux donc faire un cast.
Si C n'était pas un template, j'aurais bien casté successivement en C
puis en B, mais là, j'ai un template, dont je ne connais pas le type à
ce point du programme.
Si je fais simplement "(B *)ptr", alors "boom", il y a des décallages
d'adresses qui se passent mal, et je récupère un pointeur sur rien du
tout.
Si je fais "dynamic_cast<B *>(ptr)", ça a l'air de bien se passer (GCC
3.2).
Je dis « ça a l'air », mais justement, ce que je voudrais savoir,
c'est si il y a une bonne raison pour que ça se passe bien, et quels
risques je prends à faire ce genre de manips. (En général, ce qui
tourne autour de l'héritage multiple me fait un peu peur !)
Et accessoirement, y a-t-il une autre solution (Changer la hierarchie
de classe n'est pas une option, ce n'est pas du code à moi.) ?
Gourgouilloult <gourgou_at_club-internet_point_fr> wrote in message news:<40201e24$0$6966$...
Je pense qu'il y a un pb de conception au départ... Si on a un pointeur de If, c'est qu'on veut utiliser la partie interface des classes dérivées, pas des classes n'ayant pas de rapport avec If.
Hmm.. là, ce que tu remets en question, c'est l'utilisation de l'héritage multiple.
Quel rapport ? Dans une utilisation typique de l'héritage multiple, on dérived de plusieurs interfaces, disons If1 et If2. Les clients qui ont besoin de If1 ont des pointeurs ou des références à If1. Les clients qui ont besoin de If2 ont des pointeurs ou des références à If2. Aucun client ne sait jamais que l'objet qui implémente son interface en implémente aussi une autre.
[...]
C'est souvent dû à une erreur de conception qu'on utilise un cast.
Là, à voir la façon dont tu généralises,
Le mot « souvent » me semble indiquer que c'est une généralisation exprès -- qu'il sait que c'est une généralisation, et surtout, qu'il sait qu'elle ne s'applique pas toujours.
En tant que généralisation, je suis d'accord avec lui. Même si j'en connais des exceptions ; des cas où la généralisation ne tient pas.
-- James Kanze GABI Software mailto: Conseils en informatique orientée objet/ http://www.gabi-soft.fr Beratung in objektorientierter Datenverarbeitung 11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16
Gourgouilloult <gourgou_at_club-internet_point_fr> wrote in message
news:<40201e24$0$6966$7a628cd7@news.club-internet.fr>...
Je pense qu'il y a un pb de conception au départ... Si on a un
pointeur de If, c'est qu'on veut utiliser la partie interface des
classes dérivées, pas des classes n'ayant pas de rapport avec If.
Hmm.. là, ce que tu remets en question, c'est l'utilisation de
l'héritage multiple.
Quel rapport ? Dans une utilisation typique de l'héritage multiple, on
dérived de plusieurs interfaces, disons If1 et If2. Les clients qui ont
besoin de If1 ont des pointeurs ou des références à If1. Les clients qui
ont besoin de If2 ont des pointeurs ou des références à If2. Aucun
client ne sait jamais que l'objet qui implémente son interface en
implémente aussi une autre.
[...]
C'est souvent dû à une erreur de conception qu'on utilise un cast.
Là, à voir la façon dont tu généralises,
Le mot « souvent » me semble indiquer que c'est une généralisation
exprès -- qu'il sait que c'est une généralisation, et surtout, qu'il
sait qu'elle ne s'applique pas toujours.
En tant que généralisation, je suis d'accord avec lui. Même si j'en
connais des exceptions ; des cas où la généralisation ne tient pas.
--
James Kanze GABI Software mailto:kanze@gabi-soft.fr
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16
Gourgouilloult <gourgou_at_club-internet_point_fr> wrote in message news:<40201e24$0$6966$...
Je pense qu'il y a un pb de conception au départ... Si on a un pointeur de If, c'est qu'on veut utiliser la partie interface des classes dérivées, pas des classes n'ayant pas de rapport avec If.
Hmm.. là, ce que tu remets en question, c'est l'utilisation de l'héritage multiple.
Quel rapport ? Dans une utilisation typique de l'héritage multiple, on dérived de plusieurs interfaces, disons If1 et If2. Les clients qui ont besoin de If1 ont des pointeurs ou des références à If1. Les clients qui ont besoin de If2 ont des pointeurs ou des références à If2. Aucun client ne sait jamais que l'objet qui implémente son interface en implémente aussi une autre.
[...]
C'est souvent dû à une erreur de conception qu'on utilise un cast.
Là, à voir la façon dont tu généralises,
Le mot « souvent » me semble indiquer que c'est une généralisation exprès -- qu'il sait que c'est une généralisation, et surtout, qu'il sait qu'elle ne s'applique pas toujours.
En tant que généralisation, je suis d'accord avec lui. Même si j'en connais des exceptions ; des cas où la généralisation ne tient pas.
-- James Kanze GABI Software mailto: Conseils en informatique orientée objet/ http://www.gabi-soft.fr Beratung in objektorientierter Datenverarbeitung 11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16
Falk Tannhäuser
Alexandre wrote:
Mais ce n'est pas du tout logique : le pointeur sur If devrait être utilisé pour les fonctionnalités définies dans If, à savoir l'interface. S'il pointe sur un C<T> il est effectivement indispensable de connaitre T pour retrouver les membres de B. Je pense qu'il y a un pb de conception au départ... Si on a un pointeur de If, c'est qu'on veut utiliser la partie interface des classes dérivées, pas des classes n'ayant pas de rapport avec If. C'est souvent dû à une erreur de conception qu'on utilise un cast.
Parfois oui, parfois non.
Il y a des situations où l'utilisation du "cross cast" peut être considérée légitime, voir par exemple le "capsule pattern" : <http://www.objectmentor.com/resources/articles/crosscst.pdf>
Falk
Alexandre wrote:
Mais ce n'est pas du tout logique : le pointeur sur If devrait être utilisé
pour les fonctionnalités définies dans If, à savoir l'interface. S'il pointe
sur un C<T> il est effectivement indispensable de connaitre T pour retrouver
les membres de B.
Je pense qu'il y a un pb de conception au départ... Si on a un pointeur de
If, c'est qu'on veut utiliser la partie interface des classes dérivées, pas
des classes n'ayant pas de rapport avec If.
C'est souvent dû à une erreur de conception qu'on utilise un cast.
Parfois oui, parfois non.
Il y a des situations où l'utilisation du "cross cast" peut être
considérée légitime, voir par exemple le "capsule pattern" :
<http://www.objectmentor.com/resources/articles/crosscst.pdf>
Mais ce n'est pas du tout logique : le pointeur sur If devrait être utilisé pour les fonctionnalités définies dans If, à savoir l'interface. S'il pointe sur un C<T> il est effectivement indispensable de connaitre T pour retrouver les membres de B. Je pense qu'il y a un pb de conception au départ... Si on a un pointeur de If, c'est qu'on veut utiliser la partie interface des classes dérivées, pas des classes n'ayant pas de rapport avec If. C'est souvent dû à une erreur de conception qu'on utilise un cast.
Parfois oui, parfois non.
Il y a des situations où l'utilisation du "cross cast" peut être considérée légitime, voir par exemple le "capsule pattern" : <http://www.objectmentor.com/resources/articles/crosscst.pdf>
Falk
Gourgouilloult
Hmm.. là, ce que tu remets en question, c'est l'utilisation de l'héritage multiple.
Quel rapport ? Dans une utilisation typique de l'héritage multiple, on dérived de plusieurs interfaces, disons If1 et If2. Les clients qui ont besoin de If1 ont des pointeurs ou des références à If1. Les clients qui ont besoin de If2 ont des pointeurs ou des références à If2. Aucun client ne sait jamais que l'objet qui implémente son interface en implémente aussi une autre.
Houla, oui, j'ai peut-être extrapolé un peu vite, en effet. (En fait, quand je disais «c'est vrai que [l'héritage multiple] est rarement d'une nécessité absolue», j'aurais dû préciser que ça se rapportait surtout à mon [absence d'] expérience en la matière. Mais bon, si j'avais dit ça, il aurait fallu que je m'interdise de poster... Ah zut, maintenant je l'ai dit !)
C'est souvent dû à une erreur de conception qu'on utilise un cast.
Là, à voir la façon dont tu généralises,
Le mot « souvent » me semble indiquer que c'est une généralisation exprès -- qu'il sait que c'est une généralisation, et surtout, qu'il sait qu'elle ne s'applique pas toujours.
Je suis d'autant plus désolé d'avoir repris Alexandre que je me rends compte que c'était pour dire la même chose... (juste avec plus de mots ;-/ )
Gourgou Bouh, j'aime pas, avoir dit des bêtises !-(
Hmm.. là, ce que tu remets en question, c'est l'utilisation de
l'héritage multiple.
Quel rapport ? Dans une utilisation typique de l'héritage multiple, on
dérived de plusieurs interfaces, disons If1 et If2. Les clients qui ont
besoin de If1 ont des pointeurs ou des références à If1. Les clients qui
ont besoin de If2 ont des pointeurs ou des références à If2. Aucun
client ne sait jamais que l'objet qui implémente son interface en
implémente aussi une autre.
Houla, oui, j'ai peut-être extrapolé un peu vite, en effet. (En fait,
quand je disais «c'est vrai que [l'héritage multiple] est rarement d'une
nécessité absolue», j'aurais dû préciser que ça se rapportait surtout à
mon [absence d'] expérience en la matière. Mais bon, si j'avais dit ça,
il aurait fallu que je m'interdise de poster... Ah zut, maintenant je
l'ai dit !)
C'est souvent dû à une erreur de conception qu'on utilise un cast.
Là, à voir la façon dont tu généralises,
Le mot « souvent » me semble indiquer que c'est une généralisation
exprès -- qu'il sait que c'est une généralisation, et surtout, qu'il
sait qu'elle ne s'applique pas toujours.
Je suis d'autant plus désolé d'avoir repris Alexandre que je me rends
compte que c'était pour dire la même chose... (juste avec plus de mots ;-/ )
Gourgou
Bouh, j'aime pas, avoir dit des bêtises !-(
Hmm.. là, ce que tu remets en question, c'est l'utilisation de l'héritage multiple.
Quel rapport ? Dans une utilisation typique de l'héritage multiple, on dérived de plusieurs interfaces, disons If1 et If2. Les clients qui ont besoin de If1 ont des pointeurs ou des références à If1. Les clients qui ont besoin de If2 ont des pointeurs ou des références à If2. Aucun client ne sait jamais que l'objet qui implémente son interface en implémente aussi une autre.
Houla, oui, j'ai peut-être extrapolé un peu vite, en effet. (En fait, quand je disais «c'est vrai que [l'héritage multiple] est rarement d'une nécessité absolue», j'aurais dû préciser que ça se rapportait surtout à mon [absence d'] expérience en la matière. Mais bon, si j'avais dit ça, il aurait fallu que je m'interdise de poster... Ah zut, maintenant je l'ai dit !)
C'est souvent dû à une erreur de conception qu'on utilise un cast.
Là, à voir la façon dont tu généralises,
Le mot « souvent » me semble indiquer que c'est une généralisation exprès -- qu'il sait que c'est une généralisation, et surtout, qu'il sait qu'elle ne s'applique pas toujours.
Je suis d'autant plus désolé d'avoir repris Alexandre que je me rends compte que c'était pour dire la même chose... (juste avec plus de mots ;-/ )
Gourgou Bouh, j'aime pas, avoir dit des bêtises !-(
Matthieu Moy
Loïc Joly writes:
[...]
Sauf s'il pointe sur un C<T>. C'est un problème de vocabulaire utilisé dans la damande. On a un pointeur sur If qui pointe en réalité sur un objet du type C<T>, et on veut retrouver la partie B de cet objet.
Oui, en effet, je m'étais mal exprimé, mais c'est bien ça.
-- Matthieu
Loïc Joly <loic.actarus.joly@wanadoo.fr> writes:
[...]
Sauf s'il pointe sur un C<T>. C'est un problème de vocabulaire
utilisé dans la damande. On a un pointeur sur If qui pointe en
réalité sur un objet du type C<T>, et on veut retrouver la partie B
de cet objet.
Oui, en effet, je m'étais mal exprimé, mais c'est bien ça.
Sauf s'il pointe sur un C<T>. C'est un problème de vocabulaire utilisé dans la damande. On a un pointeur sur If qui pointe en réalité sur un objet du type C<T>, et on veut retrouver la partie B de cet objet.
Oui, en effet, je m'étais mal exprimé, mais c'est bien ça.
C'est souvent dû à une erreur de conception qu'on utilise un cast.
Là, à voir la façon dont tu généralises, j'ai le sentiment que tu parles de C-style cast. En C++, elles sont au nombre de 4, les «directives de conversion» (traduc au pif, hein). La forme à la C -la cinquième- étant la forme à éviter absolument. En l'occurence, dynamic_cast<> est ce qu'il semble falloir au PO.
Merci de tes éclaircissements.
Tu as une bonne doc à recommander là dessus ? (URL ? bouquin ?)
C'est souvent dû à une erreur de conception qu'on utilise un cast.
Là, à voir la façon dont tu généralises, j'ai le sentiment que tu
parles de C-style cast. En C++, elles sont au nombre de 4, les
«directives de conversion» (traduc au pif, hein). La forme à la C -la
cinquième- étant la forme à éviter absolument. En l'occurence,
dynamic_cast<> est ce qu'il semble falloir au PO.
Merci de tes éclaircissements.
Tu as une bonne doc à recommander là dessus ? (URL ? bouquin ?)
C'est souvent dû à une erreur de conception qu'on utilise un cast.
Là, à voir la façon dont tu généralises, j'ai le sentiment que tu parles de C-style cast. En C++, elles sont au nombre de 4, les «directives de conversion» (traduc au pif, hein). La forme à la C -la cinquième- étant la forme à éviter absolument. En l'occurence, dynamic_cast<> est ce qu'il semble falloir au PO.
Merci de tes éclaircissements.
Tu as une bonne doc à recommander là dessus ? (URL ? bouquin ?)
-- Matthieu
Gourgouilloult
Là, à voir la façon dont tu généralises, j'ai le sentiment que tu parles de C-style cast. En C++, elles sont au nombre de 4, les «directives de conversion» (traduc au pif, hein). La forme à la C -la cinquième- étant la forme à éviter absolument. En l'occurence, dynamic_cast<> est ce qu'il semble falloir au PO.
Tu as une bonne doc à recommander là dessus ? (URL ? bouquin ?)
Bah, je connais pas beaucoup de bouquins sur C++, vu que j'ai sauté dans TC++PL (http://www.research.att.com/~bs/3rd.html). L'ennui, de ce livre, si on cherche à se renseigner précisément sur les *_cast<>, c'est qu'ils sont dispersés et s'appuient sur des exemples de longue haleine (non, c'est pas français, comme expression ;).
Un autre qui a l'air bien, c'est la norme... mais il paraît que par défaut, on préfère se rabattre sur autre chose. (Au passage, je remercie Gabriel pour m'avoir fait comprendre que ce n'était pas mon cas. Ah, je l'avais déjà presque fait à l'«époque» ;) Sinon, plein de bouquins sur C++ -> accu.org
Pour te donner une petite idée des choses qui existent :
reinterpret_cast<> : dans les grandes lignes, fait la même chose qu'un cast à la C. L'avantage, c'est qu'il est un peu plus affreux, donc il se repère de loin ;
static_cast<> : ajout de contrôles de types par le compilateur ;
const_cast<> : pour passer un const quelque-chose en quelque-chose pas const (pour celui-là, j'aimerais bien un exemple d'utilisation pas affreux...) ;
et dynamic_cast<> : la vérification de la possibilité de convertir est effectuée à l'exécution (et on entend parfois dire que «c'est plus lent», mais le fait est qu'il n'y a pas forcément d'alternative, à fonctionnalité égale ;)
Ah oui, sinon, les slides de Gabriel sur codesourcery.com sont bien agréables (pour les notions de polymorphismes et tout, pas pour les casts).
Gourgou Argh, pas le temps, en retard... ça me change ;)
Là, à voir la façon dont tu généralises, j'ai le sentiment que tu
parles de C-style cast. En C++, elles sont au nombre de 4, les
«directives de conversion» (traduc au pif, hein). La forme à la C -la
cinquième- étant la forme à éviter absolument. En l'occurence,
dynamic_cast<> est ce qu'il semble falloir au PO.
Tu as une bonne doc à recommander là dessus ? (URL ? bouquin ?)
Bah, je connais pas beaucoup de bouquins sur C++, vu que j'ai sauté dans
TC++PL (http://www.research.att.com/~bs/3rd.html). L'ennui, de ce livre,
si on cherche à se renseigner précisément sur les *_cast<>, c'est qu'ils
sont dispersés et s'appuient sur des exemples de longue haleine (non,
c'est pas français, comme expression ;).
Un autre qui a l'air bien, c'est la norme... mais il paraît que par
défaut, on préfère se rabattre sur autre chose. (Au passage, je remercie
Gabriel pour m'avoir fait comprendre que ce n'était pas mon cas. Ah, je
l'avais déjà presque fait à l'«époque» ;) Sinon, plein de bouquins sur
C++ -> accu.org
Pour te donner une petite idée des choses qui existent :
reinterpret_cast<> : dans les grandes lignes, fait la même chose qu'un
cast à la C. L'avantage, c'est qu'il est un peu plus affreux, donc il se
repère de loin ;
static_cast<> : ajout de contrôles de types par le compilateur ;
const_cast<> : pour passer un const quelque-chose en quelque-chose pas
const (pour celui-là, j'aimerais bien un exemple d'utilisation pas
affreux...) ;
et dynamic_cast<> : la vérification de la possibilité de convertir est
effectuée à l'exécution (et on entend parfois dire que «c'est plus
lent», mais le fait est qu'il n'y a pas forcément d'alternative, à
fonctionnalité égale ;)
Ah oui, sinon, les slides de Gabriel sur codesourcery.com sont bien
agréables (pour les notions de polymorphismes et tout, pas pour les casts).
Gourgou
Argh, pas le temps, en retard... ça me change ;)
Là, à voir la façon dont tu généralises, j'ai le sentiment que tu parles de C-style cast. En C++, elles sont au nombre de 4, les «directives de conversion» (traduc au pif, hein). La forme à la C -la cinquième- étant la forme à éviter absolument. En l'occurence, dynamic_cast<> est ce qu'il semble falloir au PO.
Tu as une bonne doc à recommander là dessus ? (URL ? bouquin ?)
Bah, je connais pas beaucoup de bouquins sur C++, vu que j'ai sauté dans TC++PL (http://www.research.att.com/~bs/3rd.html). L'ennui, de ce livre, si on cherche à se renseigner précisément sur les *_cast<>, c'est qu'ils sont dispersés et s'appuient sur des exemples de longue haleine (non, c'est pas français, comme expression ;).
Un autre qui a l'air bien, c'est la norme... mais il paraît que par défaut, on préfère se rabattre sur autre chose. (Au passage, je remercie Gabriel pour m'avoir fait comprendre que ce n'était pas mon cas. Ah, je l'avais déjà presque fait à l'«époque» ;) Sinon, plein de bouquins sur C++ -> accu.org
Pour te donner une petite idée des choses qui existent :
reinterpret_cast<> : dans les grandes lignes, fait la même chose qu'un cast à la C. L'avantage, c'est qu'il est un peu plus affreux, donc il se repère de loin ;
static_cast<> : ajout de contrôles de types par le compilateur ;
const_cast<> : pour passer un const quelque-chose en quelque-chose pas const (pour celui-là, j'aimerais bien un exemple d'utilisation pas affreux...) ;
et dynamic_cast<> : la vérification de la possibilité de convertir est effectuée à l'exécution (et on entend parfois dire que «c'est plus lent», mais le fait est qu'il n'y a pas forcément d'alternative, à fonctionnalité égale ;)
Ah oui, sinon, les slides de Gabriel sur codesourcery.com sont bien agréables (pour les notions de polymorphismes et tout, pas pour les casts).
Gourgou Argh, pas le temps, en retard... ça me change ;)
Gabriel Dos Reis
Yannick Le goc writes:
| Dynamic_cast est une fonction complexe qui se base sur les tables | virtuelles pour retrouver ses petits.
dynamic_cast n'est pas une fonction mais un opérateur. Comment tu sais qu'il est complexe ? Et même s'il était complexe, cela ne veut pas dire qu'il n'est pas efficace -- comparé aux alternatifs.
| Ton probleme est la conversion statique de pointeurs, (conversion C (B | *)ptr a ne jamais faire en C++), en utilisant dynamic_cast tu resous a | l'execution cette conversion, qui est beaucoup plus couteuse en temps.
Mais, si le coût est nécessaire pour avoir une sémantique correcte ? dynamic_cast est le seul cast « safe », en ce sens que si tu calcules quelque chose qui n'a pas de sens, tu seras averti alors que les autres casts te laissent faire des bêtises sans rien te dire.
| Je ne comprends pas bien pourquoi tu as vraiment un probleme, car
Moi, je ne comprends pas pourquoi tu insistes sur static_cast. Pourquoi veux-tu remplacer un calcul sûr par quelque chose qui, a priori, paraît moins sûr. Tu as d'autres informations que nous n'avons pas ?
-- Gaby
Yannick Le goc <legoc@imag.fr> writes:
| Dynamic_cast est une fonction complexe qui se base sur les tables
| virtuelles pour retrouver ses petits.
dynamic_cast n'est pas une fonction mais un opérateur. Comment tu sais
qu'il est complexe ? Et même s'il était complexe, cela ne veut pas
dire qu'il n'est pas efficace -- comparé aux alternatifs.
| Ton probleme est la conversion statique de pointeurs, (conversion C (B
| *)ptr a ne jamais faire en C++), en utilisant dynamic_cast tu resous a
| l'execution cette conversion, qui est beaucoup plus couteuse en temps.
Mais, si le coût est nécessaire pour avoir une sémantique correcte ?
dynamic_cast est le seul cast « safe », en ce sens que si tu calcules
quelque chose qui n'a pas de sens, tu seras averti alors que les
autres casts te laissent faire des bêtises sans rien te dire.
| Je ne comprends pas bien pourquoi tu as vraiment un probleme, car
Moi, je ne comprends pas pourquoi tu insistes sur static_cast.
Pourquoi veux-tu remplacer un calcul sûr par quelque chose qui, a
priori, paraît moins sûr. Tu as d'autres informations que nous n'avons
pas ?
| Dynamic_cast est une fonction complexe qui se base sur les tables | virtuelles pour retrouver ses petits.
dynamic_cast n'est pas une fonction mais un opérateur. Comment tu sais qu'il est complexe ? Et même s'il était complexe, cela ne veut pas dire qu'il n'est pas efficace -- comparé aux alternatifs.
| Ton probleme est la conversion statique de pointeurs, (conversion C (B | *)ptr a ne jamais faire en C++), en utilisant dynamic_cast tu resous a | l'execution cette conversion, qui est beaucoup plus couteuse en temps.
Mais, si le coût est nécessaire pour avoir une sémantique correcte ? dynamic_cast est le seul cast « safe », en ce sens que si tu calcules quelque chose qui n'a pas de sens, tu seras averti alors que les autres casts te laissent faire des bêtises sans rien te dire.
| Je ne comprends pas bien pourquoi tu as vraiment un probleme, car
Moi, je ne comprends pas pourquoi tu insistes sur static_cast. Pourquoi veux-tu remplacer un calcul sûr par quelque chose qui, a priori, paraît moins sûr. Tu as d'autres informations que nous n'avons pas ?