OVH Cloud OVH Cloud

static_cast et ~polymorphisme

17 réponses
Avatar
Benoît Dejean
je ne m'explique pas pourquoi le code suivant compile ...

struct jobject { };

struct jclass : jobject { };
struct jother : jobject { };


jobject* factory(bool t)
{
if(t) return new jclass;

return new jother;
}


int main()
{
jobject *o = factory(false);

jclass *c = static_cast<jclass *>(o);
}

au début, je procédé sans class jother et sans factory, je me suis dit
que c'était mon compilateur qui me jouait des tour (genre il déduisait
un peu trop à mon gout)

il me semble pourtant qu'ici le static_cast est totalement incertain ...
et qu'après l'ajout d'une base virtuelle, il faudrait utiliser le
dynamic_cast ...

10 réponses

1 2
Avatar
Nomak
Le 23/06/2004 à 22:27:36, Benoît Dejean a écrit:

je ne m'explique pas pourquoi le code suivant compile ...

struct jobject { };

struct jclass : jobject { };
struct jother : jobject { };

jobject* factory(bool t)
{
if(t) return new jclass;

return new jother;
}

int main()
{
jobject *o = factory(false);

jclass *c = static_cast<jclass *>(o);
}

au début, je procédé sans class jother et sans factory, je me suis dit
que c'était mon compilateur qui me jouait des tour (genre il déduisait
un peu trop à mon gout)

il me semble pourtant qu'ici le static_cast est totalement incertain ...
et qu'après l'ajout d'une base virtuelle, il faudrait utiliser le
dynamic_cast ...


Oui ton code est faux.

Avec un static_cast ou un reinterpret_cast, tu dis à ton compilo que
tu sais que ça va marcher, et qu'il n'a pas besoin de vérifier (en
gros).

Ici tu dois utiliser un dynamic_cast pour lui demander de vérifier le
cast (renvoie NULL si le cast échoue).

--
Nomak

Avatar
Benoît Dejean
Le Wed, 23 Jun 2004 23:24:43 +0200, Nomak a écrit :

Le 23/06/2004 à 22:27:36, Benoît Dejean a écrit:

je ne m'explique pas pourquoi le code suivant compile ...


Oui ton code est faux.

Avec un static_cast ou un reinterpret_cast, tu dis à ton compilo que
tu sais que ça va marcher, et qu'il n'a pas besoin de vérifier (en
gros).


la preuve

Ici tu dois utiliser un dynamic_cast pour lui demander de vérifier le
cast (renvoie NULL si le cast échoue).


ça je le sais et je le comprends bien, je me demande juste pourquoi mon
compilateur (gcc-3.[34]) accepte ça ... Comeau online n'y trouve rien à
redire.


Avatar
Nomak
Le 24/06/2004 à 07:21:51, Benoît Dejean a écrit:

Le Wed, 23 Jun 2004 23:24:43 +0200, Nomak a écrit :

Le 23/06/2004 à 22:27:36, Benoît Dejean a écrit:

je ne m'explique pas pourquoi le code suivant compile ...


Oui ton code est faux.

Avec un static_cast ou un reinterpret_cast, tu dis à ton compilo que
tu sais que ça va marcher, et qu'il n'a pas besoin de vérifier (en
gros).


la preuve

Ici tu dois utiliser un dynamic_cast pour lui demander de vérifier le
cast (renvoie NULL si le cast échoue).


ça je le sais et je le comprends bien, je me demande juste pourquoi mon
compilateur (gcc-3.[34]) accepte ça ... Comeau online n'y trouve rien à
redire.


Parcequ'il respecte la norme et la norme dit un "static_cast sait ce
qu'il fait". Il ne _doit pas_ vérifier, c'est ce que tu demande en
utilisant ce type de cast.


--
Nomak



Avatar
Horst Kraemer
On Wed, 23 Jun 2004 22:27:36 +0200, Benoît Dejean
wrote:

je ne m'explique pas pourquoi le code suivant compile ...

struct jobject { };

struct jclass : jobject { };
struct jother : jobject { };

jobject* factory(bool t)
{
if(t) return new jclass;

return new jother;
}


int main()
{
jobject *o = factory(false);

jclass *c = static_cast<jclass *>(o);
}


Il n'y aucune raison pour laquelle ce code ne devrait pas compiler.
Un static_cast d'un pointeur à jobject vers un pointeur à jclass est
légal selon la norme du langage C++ - mais le comportement du
programme est indéfini si l'objet auquel le pointeur pointe n'est pas
un objet du type jclass ou un objet d'une classe dérivée de jclass.
Donc l'usage "légal" de ce static_cast est limité à des cas ou le
programmeur sait que l'objet auquel le pointeur pointe à un "bon"
type.

Si tu veux vérifier si l'objet auquel le pointeur pointe a un "bon"
type il faut utiliser dynamic_cast (et il faut que la base ait une
fonction virtuelle).

C++ ne te fait pas payer ce que tu ne veux pas. Si tu dis static_cast
tu ne payes pas les couts de dynamic_cast - mais c'est à toi de
garantir que l'effet du cast a un sens.

--
Horst

Avatar
Fabien LE LEZ
On Thu, 24 Jun 2004 15:01:56 +0200, Horst Kraemer
:

Donc l'usage "légal" de ce static_cast est limité à des cas ou le
programmeur sait que l'objet auquel le pointeur pointe à un "bon"
type.


D'où d'ailleurs le nom, "static" signifiant ici "connu à la
compilation".


--
schtroumpf schtroumpf

Avatar
Benoît Dejean
Le Thu, 24 Jun 2004 16:18:20 +0200, Fabien LE LEZ a écrit :

On Thu, 24 Jun 2004 15:01:56 +0200, Horst Kraemer
:

Donc l'usage "légal" de ce static_cast est limité à des cas ou le
programmeur sait que l'objet auquel le pointeur pointe à un "bon"
type.


D'où d'ailleurs le nom, "static" signifiant ici "connu à la
compilation".


ok :D

il n'empêche, j'ai du mal à comprendre l'intérêt d'une telle chose si
ce n'est créer des problèmes :D
comme me l'a une fois du GdR, « si la norme le dit ... » ou je sais plus
d'ailleurs, bref qu'évidemment la norme est parole de
vérité/espérance/qu'importe

j'ai une autre question parente

que ce passe-t-il lors d'un *_cast<Base*>( p );
ou p est un un Derive* ne pointant pas vers un objet (0 ou n'importe quoi) ?
est-ce un UB, y a-t-il plusieurs cas à discerner ?


Avatar
Fabien LE LEZ
On Thu, 24 Jun 2004 19:43:38 +0200, Benoît Dejean :

ou p est un un Derive* ne pointant pas vers un objet (0 ou n'importe quoi) ?
est-ce un UB, y a-t-il plusieurs cas à discerner ?


Si p est un pointeur non NULL, qui ne pointe pas vers un objet (ou
vers le successeur d'un objet, i.e. &objet + 1), il me semble qu'on a
un comportement indéfini de toutes façons...


--
schtroumpf schtroumpf

Avatar
Benoît Dejean
Le Thu, 24 Jun 2004 21:04:17 +0200, Fabien LE LEZ a écrit :

On Thu, 24 Jun 2004 19:43:38 +0200, Benoît Dejean :

ou p est un un Derive* ne pointant pas vers un objet (0 ou n'importe quoi) ?
est-ce un UB, y a-t-il plusieurs cas à discerner ?


Si p est un pointeur non NULL, qui ne pointe pas vers un objet (ou
vers le successeur d'un objet, i.e. &objet + 1), il me semble qu'on a
un comportement indéfini de toutes façons...


mais si p est NULL / 0 que te semble-t-il ? que le cast renverra
invariablement 0 ?


Avatar
Falk Tannhäuser
Benoît Dejean wrote:


On Thu, 24 Jun 2004 19:43:38 +0200, Benoît Dejean :

ou p est un un Derive* ne pointant pas vers un objet (0 ou n'importe quoi) ?
est-ce un UB, y a-t-il plusieurs cas à discerner ?


Si p est un pointeur non NULL, qui ne pointe pas vers un objet (ou
vers le successeur d'un objet, i.e. &objet + 1), il me semble qu'on a
un comportement indéfini de toutes façons...


mais si p est NULL / 0 que te semble-t-il ? que le cast renverra
invariablement 0 ?


Oui, c'est ce que dit la Norme (5.2.9/8).

Falk



Avatar
kanze
Benoît Dejean wrote in message
news:...

On Thu, 24 Jun 2004 15:01:56 +0200, Horst Kraemer
:

Donc l'usage "légal" de ce static_cast est limité à des cas ou le
programmeur sait que l'objet auquel le pointeur pointe à un "bon"
type.


D'où d'ailleurs le nom, "static" signifiant ici "connu à la
compilation".


ok :D

il n'empêche, j'ai du mal à comprendre l'intérêt d'une telle chose si
ce n'est créer des problèmes :D


I'intérêt d'un static_cast sur des pointeurs est assez limités, mais il
y a des cas quand même, ou tu sais bien quel est le type réel d'où est
provenu le void*, par exemple. (Avec void*, évidemment, tu ne peux pas
utiliser un dynamic_cast.)

comme me l'a une fois du GdR, « si la norme le dit ... » ou je sais
plus d'ailleurs, bref qu'évidemment la norme est parole de
vérité/espérance/qu'importe


C'est la bible d'une réligion:-). Le but, c'est qu'il fasse aussi partie
du contrat entre les fournisseurs des compilateurs et les utilisateurs.
Pour l'instant, malheureusement, on n'est pas encore là.

j'ai une autre question parente

que ce passe-t-il lors d'un *_cast<Base*>( p );
ou p est un un Derive* ne pointant pas vers un objet (0 ou n'importe
quoi) ?


Si p est un pointeur nul, le résultat est un pointeur nul du nouveau
type.

Si p designe l'élément un au delà de la fin d'un tableau, c'est une
bonne question. Je n'ai pas la moindre idée, et je ne trouve pas de
réponse rapide dans la norme.

Si p ne designe pas réelement un objet, n'est pas un pointeur nul, et ne
pointe pas à l'élément fictif un au delà de la fin d'un table, le fait
simplement de le lire est un comportement indéfini.

est-ce un UB, y a-t-il plusieurs cas à discerner ?


C'est du C++. Il y a toujours plusieurs cas à discerner. Il ne faut pas
faire simple quand on peut faire compliquer, non.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34



1 2