OVH Cloud OVH Cloud

Transformer une instance d'une classe en une instance d'une autre classe ?

8 réponses
Avatar
Matthieu Fleurent
Bonsoir (ou bonjour).
La question sera sûrement bête mais je bloque, donc je me lance.

Mise en scène :
- Une classe "Point" ;
- Une classe "PointColoré" qui hérite de "Point" ;
- Une classe "PointNommé" qui hérite de "Point ;
- "P" est une instance de "Point".

But :
Au cours de l'exécution de mon programme, j'aimerais que "P" devienne
soit une instance de "PointColoré", soit une instance de "PointNommé"
(en fonction d'une condition "X"), tout en conservant ses anciennes
propriétés.

J'ai cherché du côté du transtypage (puisqu'il me semble qu'on est en
plein dedans) mais je n'ai pas réussi à mettre le bidule en oeuvre.
Quelqu'un saura-t'il m'éclairer ? Et m'indiquer les éventuels prérequis
qu'il faudrait mettre en place dans mes classes "Point", "PointColoré"
et "PointNommé" (du genre un constructeur de tel type, un opérateur qui
fait cela, etc.) ?

Toute aide sera grandement appréciée.
Merci d'avance et bonne soirée à vous.

--
Matthieu FLEURENT

8 réponses

Avatar
Fabien LE LEZ
On Wed, 01 Mar 2006 22:17:15 +0100, Matthieu Fleurent
:

- "P" est une instance de "Point".


Je suppose que P est bien un objet de type "Point", pas un pointeur
(ou une référence) de type Point* qui pointe sur un objet de type
PointColoré.

Au cours de l'exécution de mon programme, j'aimerais que "P" devienne
soit une instance de "PointColoré", soit une instance de "PointNommé"
(en fonction d'une condition "X"), tout en conservant ses anciennes
propriétés.


Ce n'est pas possible. Si "P" est un objet de type "Point", il le
reste toute sa vie.

Par contre, tu peux créer un objet de type "PointColoré" par copie de
P -- il suffit que la classe PointColoré ait un constructeur acceptant
comme argument un "Point".

Exemple :

class Point { ... };

class PointColoré
// : public Point /* Je mets ceci en commentaire car c'est
indépendant du problème */
{
public:
PointColoré (Point const&);
};

Avatar
Matthieu Fleurent
Fabien LE LEZ wrote:
- "P" est une instance de "Point".


Je suppose que P est bien un objet de type "Point", pas un pointeur
(ou une référence) de type Point* qui pointe sur un objet de type
PointColoré.


Effectivement, c'est tout à fait ça.

Au cours de l'exécution de mon programme, j'aimerais que "P" devienne
soit une instance de "PointColoré", soit une instance de "PointNommé"
(en fonction d'une condition "X"), tout en conservant ses anciennes
propriétés.


Ce n'est pas possible. Si "P" est un objet de type "Point", il le
reste toute sa vie.


OK, merci, c'est compris.

Par contre, tu peux créer un objet de type "PointColoré" par copie de
P -- il suffit que la classe PointColoré ait un constructeur acceptant
comme argument un "Point".

Exemple :

class Point { ... };

class PointColoré
// : public Point /* Je mets ceci en commentaire car c'est
indépendant du problème */
{
public:
PointColoré (Point const&);
};


OK, ça m'aide énormément. J'y avais songé mais je pensais que le
"transtypage" était possible et était plus efficace (pas de copie du
point P mais réutilisation et extension de l'existant) et j'avais donc
laissé cette voie de côté.

Et du coup, je peux donc appeler le destructeur de "Point" sur P une
fois que j'ai appelé ce constructeur (vu que je ne me sers plus du point
P, ses données ayant été copiées dans mon nouveau point de type
"PointColoré") ?


Merci beaucoup pour la réponse rapide et très claire.
Bonne soirée :).


Avatar
Fabien LE LEZ
On Wed, 01 Mar 2006 23:09:19 +0100, Matthieu Fleurent
:

Et du coup, je peux donc appeler le destructeur


Je ne sais pas si c'est un problème de vocabulaire ou de
compréhension, mais on n'appelle *pas* un destructeur.

(Sauf peut-être quand on a créé un objet avec le "placement new" --
mais j'avoue que cette partie est très floue pour moi.)

de "Point" sur P une fois que j'ai appelé ce constructeur


Idem, on n'appelle jamais un constructeur.

Si tu crées ton objet de type PointColoré, et que tu n'as plus besoin
de ton objet P, tu peux éventuellement décider de le détruire. Mais
encore faut-il en avoir la possibilité.

Exemple :

void f (Point const& P)
{
PointColoré pc (P);
// Ici, utilisation de pc
}

void g()
{
Point P;
f (P);
}

Dans ce cas précis, P sera détruit à la sortie de g(). Tu ne peux pas
le détruire toi-même.

On pourrait éventuellement faire un truc comme ça :

void f (Point*& ptr)
{
PointColoré pc (*ptr);
delete ptr;
// Ici, utilisation de pc
}

void g()
{
Point* ptr= new Point;
f (ptr);
}

mais c'est horriblement casse-gueule.

Avatar
kanze
Fabien LE LEZ wrote:
On Wed, 01 Mar 2006 22:17:15 +0100, Matthieu Fleurent
:

- "P" est une instance de "Point".


Je suppose que P est bien un objet de type "Point", pas un
pointeur (ou une référence) de type Point* qui pointe sur un
objet de type PointColoré.

Au cours de l'exécution de mon programme, j'aimerais que "P"
devienne soit une instance de "PointColoré", soit une
instance de "PointNommé" (en fonction d'une condition "X"),
tout en conservant ses anciennes propriétés.


Ce n'est pas possible. Si "P" est un objet de type "Point", il
le reste toute sa vie.


Au niveau du langage, tu as bien raison. Mais avec l'idiome
lettre/envellope, on peut faire en sort que P se comporte
parfois comme un PointColoré parfois comme un PointNommé, selon
ce qui lui a été affecté.

--
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


Avatar
Matthieu Fleurent
Fabien LE LEZ wrote:
Et du coup, je peux donc appeler le destructeur


Je ne sais pas si c'est un problème de vocabulaire ou de
compréhension, mais on n'appelle *pas* un destructeur.


Je sais que le destructeur est "appelé" automatiquement (mon cours fait
bien mention "d'appeler") et je pensais donc qu'il était possible de
forcer cet "appel" lorsque nécessaire. J'oublie donc cette possibilité.

de "Point" sur P une fois que j'ai appelé ce constructeur


Idem, on n'appelle jamais un constructeur.


Là par contre, c'était effectivement un soucis de vocabulaire.

Si tu crées ton objet de type PointColoré, et que tu n'as plus besoin
de ton objet P, tu peux éventuellement décider de le détruire. Mais
encore faut-il en avoir la possibilité.
[...]
mais c'est horriblement casse-gueule.


C'est noté, je vais donc éviter.

J'en ai profité pour lire ceci :
http://c.developpez.com/faq/cpp/?pageÞstructeur
C'est, je trouve, nettement plus clair que le cours dont je dispose (du
moins en ce qui concerne les destructeurs).Ca répond à pas mal de
questions tordues.

Merci beaucoup pour ta patience et le temps que tu m'as accordé :).


Avatar
Alexandre

Je ne sais pas si c'est un problème de vocabulaire ou de
compréhension, mais on n'appelle *pas* un destructeur.


on peut, c'est légal même si je n'ai encore jamais trop vu de situation où
c'est utile...

ceci dit, quand on fait :
delete p
on appelle bien le destructeur explicitement ;-), non ?
bon je pinaille ;-)

Avatar
Laurent Deniau
Matthieu Fleurent wrote:
Bonsoir (ou bonjour).
La question sera sûrement bête mais je bloque, donc je me lance.

Mise en scène :
- Une classe "Point" ;
- Une classe "PointColoré" qui hérite de "Point" ;
- Une classe "PointNommé" qui hérite de "Point ;
- "P" est une instance de "Point".

But :
Au cours de l'exécution de mon programme, j'aimerais que "P" devienne
soit une instance de "PointColoré", soit une instance de "PointNommé"
(en fonction d'une condition "X"), tout en conservant ses anciennes
propriétés.

J'ai cherché du côté du transtypage (puisqu'il me semble qu'on est en
plein dedans) mais je n'ai pas réussi à mettre le bidule en oeuvre.
Quelqu'un saura-t'il m'éclairer ? Et m'indiquer les éventuels prérequis
qu'il faudrait mettre en place dans mes classes "Point", "PointColoré"
et "PointNommé" (du genre un constructeur de tel type, un opérateur qui
fait cela, etc.) ?


Ce que tu demandes s'appelle l'heritage dynamique et ce n'est pas
possible en C++. C'est une fonctionnalite generalement proposee par les
langage a typage dynamique (CLOS) ou a prototype (Cecil, Slate) ou ayant
des contructions specifiques comme les classes virtuelles (gbeta ou
CaesarJ). Si c'est un sujet qui t'interesse, tu peux regarder les
travaux de E. Ernst ("Safe dynamic multiple inheritance" et "A virtual
class calculus").

En C++ il faut utiliser un design pattern comme le bridge par exemple.

a+, ld.

Avatar
Fabien LE LEZ
On Thu, 2 Mar 2006 15:55:17 +0100, "Alexandre"
:

on peut, c'est légal


Appeler gets() aussi, c'est légal...

même si je n'ai encore jamais trop vu de situation où
c'est utile...


J'imagine que std::vector<> s'en sert.

ceci dit, quand on fait :
delete p
on appelle bien le destructeur explicitement ;-), non ?


Non. Implicitement.

Appeler une fonction explicitement, c'est écrire son nom.
Par exemple :
f();

Appeler explicitement un destructeur, c'est écrire :
mon_objet.~MaClasse();