OVH Cloud OVH Cloud

Polymorphisme, sémantique de valeur, durée de vie des temporaires...

38 réponses
Avatar
Marc Boyer
Bonjour,

j'ai un problème 'pure virtual method called' (avec g++), et je n'arrive
pas à faire d'exemple minimal qui reproduise le pb...

Mais j'ai peut etre identifié le pb. Quand j'écris un truc du genre
X x( Y(1) );
avec X et Y deux classes, quelle est la durée de vie de l'objet
temporaire Y ?

Actuellement, je prends une référence sur cet objet, et visiblement
il aime pas. Alors que si j'écris
X x( *(new Y(1)) );
ça marche bien.

Merci,

Marc Boyer
--
Si tu peux supporter d'entendre tes paroles
Travesties par des gueux pour exciter des sots
IF -- Rudyard Kipling (Trad. André Maurois)

8 réponses

1 2 3 4
Avatar
Marc Boyer
Le 07-03-2007, Sylvain a écrit :
Marc Boyer wrote on 07/03/2007 20:46:

Oui, ça je sais. Puis Laurent m'a dit "Probleme ici. Il ne faut pas
utiliser des references mais des copies.", et c'est pour cela que j'ai
évoqué la perte du polymorphisme.


aurait-il du préciser "copie statique pouvant réellement exister" ??


Je ne sais pas, il faudrait lui demander. Il me semble que dans
mon échange avec Laurent, nous nous sommes compris tous les deux.

utiliser des réf., des pointeurs ou des statiques ne change rien au
polymorphisme des instances et n'a en fait rien à voir avec lui !!


Ah.

ayant:
struct A {
virtual foo() {}
};
struct B : A {
};
struct C : B {
virtual foo() {}
};

A a;
B b;
C c;

A& ra = a; // ou ra = b; ou ra = c;
B& rb = b; // ou rb = c;
C& rc = c;

A* pa = &a; // ou pa = &b; ou pa = &c;
B* pb = &b; // ou pb = &c;
C* pc = &c;

tous les appels:

a.foo(); b.foo(); c.foo();
ra.foo(); rb.foo(); rc.foo();
pa->foo(); pb->foo(); pc->foo();

sont résolus virtuellement et tiennent compte du polymorphisme.

tu sembles faire une distinction comme:

void bar(A& a) { a.foo(); }
bar(c); // ohhh du polymorphisme

vs

B b;
b.foo(); // ne serait pas polymorphe


Oui.

une telle définition serait un non sens


C'est là que je demande des précisions.

- et à ce titre on parle de
polymorphisme plus volontiers pour des types containers construits sur
le type de base de la famille de classes polymorphes (Cf "ma belle
listée chainée polymorphique", parutions diverses, 1988-1990).


Là, je ne comprends pas.

Google sait retrouver un post à partir d'un ID si tu veux.


s'il a été indéxé, tu sais ce n'est pas tout à fait immédiat.


C'est néanmoins assez rapide.

Sauf que dans l'ECM que je viens de poster, c'est
struct Fonction {
virtual double operator()(double x) const { assert(false); return 0;};
// La fonction virtuelle pure remplacee par une fct reelle pour
// que ça compile


peut être cela commençait à être un peu trop noyé de "et si" pour que je
note cette variation ...


C'est pour cela que j'avais pris la peine de faire un ECM et pas un
"et si" suplémentaire sans le contexte.

le proto de () (pour ne parler que de lui) serait également non élégant,
ici Fonction /est/ virtuelle pure par essence;


Nous sommes d'accord. C'est d'ailleurs le sens de mon commentaire.

Oui, comme on tourne autour d'une solution, il y a diverses versions,
mais le post auquel tu viens de repondre possède un ECM ou Fonction
n'est pas virtuelle pure.


cette variante n'est pas une solution, seulement une machine à produire
des assert de manière certaine (cf "dans un "Fonction" on ne stocke
qu'un "Fonction");


C'est un code qui est juste destiné à visualiser quelle fonction
est réellement appellée. J'aurais pu faire un
'cout<<"Fonction::()<<endl' aussi.

Tient, il garantie pas de n'appeller les destructeur qu'à la fin
du bloc courant ?


pour autant que l'on puisse définir bloc courant, si; mais jouer ainsi
avec des définitions variantes est risqué - je préfère franchement
définir /son/ bloc courant à sa portée d'utilisation (et elle s'arrête
dans le constructeur).


Donc, quand je fais
void toto(){
Affine a1(1);
Affine a2(2);
Min m(a1,a2);
// utilisation de m
}
tout va bien dans toto.

ces instances jamais détruites.
Quel est le risque ?



aucun si tes codes ne tournent qu'une fois, mais c'est juste une très
mauvaise habitude / attitude.


Je sais.

Marc Boyer
--
Si tu peux supporter d'entendre tes paroles
Travesties par des gueux pour exciter des sots
IF -- Rudyard Kipling (Trad. André Maurois)



Avatar
James Kanze
On Mar 7, 8:46 pm, Marc Boyer
wrote:
Le 07-03-2007, Sylvain a écrit :

Marc Boyer wrote on 07/03/2007 17:19:
[...]


class Min : public Fonction {
const Fonction& f;
const Fonction& g;



Oui, ça je sais. Puis Laurent m'a dit "Probleme ici. Il ne faut pas
utiliser des references mais des copies.", et c'est pour cela que j'ai
évoqué la perte du polymorphisme.


Juste un rappel, mais l'idiome lettre/enveloppe permet la
polymorphisme avec une sémantique de valeur. (Que tu n'aies pas
envie d'une chose aussi lourde dans un programme jetable, je
comprends bien.)

--
James Kanze (GABI Software) email:
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



Avatar
James Kanze
On Mar 7, 5:28 pm, Marc Boyer
wrote:

Alors je pourrais sortir l'artillerie des pointeurs, ou de methode
..clone(), mais j'ai la flemme. C'est du code jetable.


des données membre pointeurs sont pourtant la bonne solution, leur
initialisation, utilisation peut selon le nombre d'occurrence être
doublonné avec des refs pour s'épargner qlq déréférencements.


Dans de tels cas, ça m'arrive souvent de faire que le paramètre
et la variable membre sont des std::auto_ptr. Quand je fais
vite, et que je n'ai pas le collecteur de Boehm sous la main,
évidemment. Si j'ai Boost installé, je pourrais aussi préférer
boost::shared_ptr dans ce cas précis. (Ce n'est pas une réponse
universelle à l'absence du GC, mais dans le cas des agents
polymorphe, il est tout à fait indiqué.)


Mais dans les deux cas, à l'appel, il faudrait faire un appel
avec un new, non ?
Min m( new Affine(2), new Affine(3));


Certes. Je crois même qu'il faut écrire :

Min m( std::auto_ptr< Function >( new Affine( 2 ) ),
std::auto_ptr< Function >( new Affine( 3 ) ) ) ;

parce qu'il n'y a pas de conversion implicite.

C'est précisement ce genre de problème qui m'a motivé à utiliser
le collecteur de Boehm (qui ferait probablement partie de la
prochaine version du C++ standard).

--
James Kanze (GABI Software) email:
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




Avatar
James Kanze
On Mar 7, 7:39 pm, Sylvain wrote:

[...]
pourquoi pas, je n'ai jamais utilisé ces auto ou shared ptr, ni jamais
regretter l'absence d'un GC, mais pour qui ne veut/sait pas gérer
correctement un pointeur, c'est sûrement bien.


Pourquoi s'emmerder, s'il existe un automatisme qui le fait
mieux ? (Ceci dit, si on ne *sait* pas gérer, le code finira
par ne pas marcher, automatisme ou non, parce qu'on y compterait
quand il ne faut pas. Quand on sait, en revanche, pourquoi pas
réduire le travail ?)

--
James Kanze (GABI Software) email:
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

Avatar
Marc Boyer
Le 08-03-2007, James Kanze a écrit :
On Mar 7, 5:28 pm, Marc Boyer
wrote:
Mais dans les deux cas, à l'appel, il faudrait faire un appel
avec un new, non ?
Min m( new Affine(2), new Affine(3));


Certes. Je crois même qu'il faut écrire :

Min m( std::auto_ptr< Function >( new Affine( 2 ) ),
std::auto_ptr< Function >( new Affine( 3 ) ) ) ;

parce qu'il n'y a pas de conversion implicite.


Là, il devient nécessaire de fournir les fonctions qui
encapsule tout ça:
std::auto_ptr< Function > ptAffine( double );

C'est précisement ce genre de problème qui m'a motivé à utiliser
le collecteur de Boehm (qui ferait probablement partie de la
prochaine version du C++ standard).


OK

Marc Boyer
--
Si tu peux supporter d'entendre tes paroles
Travesties par des gueux pour exciter des sots
IF -- Rudyard Kipling (Trad. André Maurois)


Avatar
Sylvain
Marc Boyer wrote on 08/03/2007 09:03:

B b;
b.foo(); // ne serait pas polymorphe
Oui.


une telle définition serait un non sens
C'est là que je demande des précisions.


- et à ce titre on parle de
polymorphisme [] pour des types containers


Là, je ne comprends pas.


soit, mais ? et ? je ne sais pas répondre à "je ne comprends pas" qui
n'est pas une question ...

si tu comprends polymorphisme seulement par "dynamic binding" alors
(comme sûrement présent dans la FAQ) stricto sensus cela ne concerne
qu'un pointeur (ou une réf.) pas une var. statique; pour autant ce qui
permet cet appel polymorphe est évidemment également présent dans cette
variable statique; d'où mon point: le langage est polymorphe, pas telle
ou telle variable selon la façon dont j'y accède.

Sylvain.


Avatar
Marc Boyer
Le 08-03-2007, Sylvain a écrit :
Marc Boyer wrote on 08/03/2007 09:03:
- et à ce titre on parle de
polymorphisme [] pour des types containers


Là, je ne comprends pas.


soit, mais ? et ? je ne sais pas répondre à "je ne comprends pas" qui
n'est pas une question ...


:-)

si tu comprends polymorphisme seulement par "dynamic binding" alors
(comme sûrement présent dans la FAQ) stricto sensus cela ne concerne
qu'un pointeur (ou une réf.) pas une var. statique;


Bien. Le terme polymorphisme n'apparaît pas dans la FAQ. Ceci dit,
oui, il me semble qu'il existe un consensus dans la communauté C++
pour associer polymorphisme (dynamique) à "dynamic binding", et,
peut-être de façon moins claire, polymorphisme statique à "template",
et comme je postais sur fclc++, et que je contexte écartait clairement
les templates, je me suis servis de "polymorphisme".

Et dans ma version (française) de TC++PL, oui (§12.2), le
mot polymorphisme est utilisé pour parler du dynamic binding.

pour autant ce qui
permet cet appel polymorphe est évidemment également présent dans cette
variable statique;


Ah ? Pourquoi ? Le compilo sachant très bien quelle fonction sera
appelée, il me semble qu'il peut tout à fait se passer là de
l'artillerie du polymorphisme dynamique et coder directement l'appel
à Fonction::operator().
D'ailleurs, mon TC++PL, toujours dans le même paragraphe, dit
bein que "Lorsqu'on manipule un objet directement (...) son type
exact est connu par le compilateur et le polymorphisme n'est plus
n"cessaire à l'exécution".

d'où mon point: le langage est polymorphe, pas telle
ou telle variable selon la façon dont j'y accède.


Non, je ne suis pas d'accord.

Marc Boyer
--
Si tu peux supporter d'entendre tes paroles
Travesties par des gueux pour exciter des sots
IF -- Rudyard Kipling (Trad. André Maurois)



Avatar
Laurent Deniau
Marc Boyer wrote:
Marc Boyer wrote on 08/03/2007 09:03:
- et à ce titre on parle de
polymorphisme [] pour des types containers
Là, je ne comprends pas.

soit, mais ? et ? je ne sais pas répondre à "je ne comprends pas" qui

n'est pas une question ...


:-)

si tu comprends polymorphisme seulement par "dynamic binding" alors
(comme sûrement présent dans la FAQ) stricto sensus cela ne concerne
qu'un pointeur (ou une réf.) pas une var. statique;


Bien. Le terme polymorphisme n'apparaît pas dans la FAQ. Ceci dit,
oui, il me semble qu'il existe un consensus dans la communauté C++
pour associer polymorphisme (dynamique) à "dynamic binding", et,
peut-être de façon moins claire, polymorphisme statique à "template",
et comme je postais sur fclc++, et que je contexte écartait clairement
les templates, je me suis servis de "polymorphisme".

Et dans ma version (française) de TC++PL, oui (§12.2), le
mot polymorphisme est utilisé pour parler du dynamic binding.


A ce titre tu peux lire la section 1.2 du fichier object_model.html dans

http://ldeniau.web.cern.ch/ldeniau/oopc.html#CPPObjModel

En C++, un objet est definit comme polymorphe s'il a un lien vers les
informations de sa classe, c'est a dire qu'il a soit une fonction membre
virtual, soit une classe de base virtual[1] soit les deux. C'est une
condition essentielle pour que typeid et dynamic_cast fonctionnent
correctement.

D'autre part, je pense effectivement que c'est important de restreintre
le terme de polymorphisme au seul polymorphisme d'inclusion parce que
C++ est un est rare langage a implementer les 4 polymorphismes de la
classification de Cardelli et donc il faudrait sans arret preciser
duquel on parle a chaque fois, ce qui ne simplifierait pas le texte.

[1] ce point c'est moi qu'il est ajoute car je trouvais la definition de
la norme incomplete pour le decrire le modele objet (voir definition 1.1
du papier suscite).

a+, ld.




1 2 3 4