Bonsoir, que ce soit avec VC++ ou gcc, le code suivant ne compile pas
(ou plus exactement ne linke pas...)
est-ce un non respect de la norme ou de la syntaxe de ma part ou un
défaut d'implémentation des compilos ?
cordialement,
MP
#include <iostream>
//************************ classe de base ********************************
template <class T>
class ISeq
{
public:
Il me semble que les destructeurs doivent forcément avoir une implémentation, même si on ajoute '= 0' à la définition.
Ou as-tu implémenté ces fonctions ? L'erreur au link ne serait pas qu'il manque les fonctions SeqX::SeqX et SeqX::~SeqX ?
A+
Christophe
c'est le cas... il sont implémentés si tu regardes le code fourni l'erreur se produit au link et est relative à la première instruction d'affectation du main
oui, j'ai vu mais un peu tard. Je me suis fais avoir parce que certaines fonctions étaient implémentées directement dans la déclaration de la classe... J'ai lu un peu vite :-)
A+
Christophe
-- Christophe de Vienne Experience is something you don't get until just after you need it. Oliver's Law.
Mathieu Peyréga wrote:
Il me semble que les destructeurs doivent forcément avoir une
implémentation, même si on ajoute '= 0' à la définition.
Ou as-tu implémenté ces fonctions ? L'erreur au link ne serait pas qu'il
manque les fonctions SeqX::SeqX et SeqX::~SeqX ?
A+
Christophe
c'est le cas... il sont implémentés si tu regardes le code fourni
l'erreur se produit au link et est relative à la première instruction
d'affectation du main
oui, j'ai vu mais un peu tard. Je me suis fais avoir parce que certaines
fonctions étaient implémentées directement dans la déclaration de la
classe... J'ai lu un peu vite :-)
A+
Christophe
--
Christophe de Vienne
Experience is something you don't get until just after you need it.
Oliver's Law.
Il me semble que les destructeurs doivent forcément avoir une implémentation, même si on ajoute '= 0' à la définition.
Ou as-tu implémenté ces fonctions ? L'erreur au link ne serait pas qu'il manque les fonctions SeqX::SeqX et SeqX::~SeqX ?
A+
Christophe
c'est le cas... il sont implémentés si tu regardes le code fourni l'erreur se produit au link et est relative à la première instruction d'affectation du main
oui, j'ai vu mais un peu tard. Je me suis fais avoir parce que certaines fonctions étaient implémentées directement dans la déclaration de la classe... J'ai lu un peu vite :-)
A+
Christophe
-- Christophe de Vienne Experience is something you don't get until just after you need it. Oliver's Law.
Christophe Lephay
"DG" a écrit dans le message de news:
writes:
Quand tu fais « *pA = *pB », tu affectes un Seq2 à un Seq1. Le compilateur résoud le surcharge en faveur de l'affectation par copie (Seq1 étant une base de Seq2), et essaie donc de générer une implémentation implicitement aussi. Et c'est là que le bat blesse -- la version générée appelle les opérateurs d'affectation des classes de base.
Pour ma part, j'ai un peu de mal à comprendre là. Si je t'ai bien suivi, le compilateur génère implicitement l'implémentation suivante: ISeq1& operator=( ISeq1 const& );
et c'est cette implémentation qui est utilisée lors du « *pA = *pB » alors pourquoi a-t-on aussi besoin de d'une implémentation de l'opérateur d'affectation dans les classes de bases ? Est-ce que c'est le même mécanisme que lorsqu'une classe B hérite d'une classe A, lors de l'instanciation d'un objet de type B, la constructeur de A puis celui de B est appelé ?
*pA = *pB; est équivalent à *pA.operator=( *pB );
L'opérateur d'affectation appelé est donc celui qui se trouve dans la classe Seq1, dans laquelle on se connait rien de Seq2...
Chris
"DG" <dany42NOSPAM@free.fr> a écrit dans le message de
news:86isng7z2q.fsf@macphisto.homeunix.org...
kanze@gabi-soft.fr writes:
Quand tu fais « *pA = *pB », tu affectes un Seq2 à un Seq1. Le
compilateur résoud le surcharge en faveur de l'affectation par copie
(Seq1 étant une base de Seq2), et essaie donc de générer une
implémentation implicitement aussi. Et c'est là que le bat blesse -- la
version générée appelle les opérateurs d'affectation des classes de
base.
Pour ma part, j'ai un peu de mal à comprendre là. Si je t'ai bien suivi,
le compilateur génère implicitement l'implémentation suivante:
ISeq1& operator=( ISeq1 const& );
et c'est cette implémentation qui est utilisée lors du « *pA = *pB »
alors pourquoi a-t-on aussi besoin de d'une implémentation de
l'opérateur d'affectation dans les classes de bases ? Est-ce que c'est
le même mécanisme que lorsqu'une classe B hérite d'une classe A, lors
de l'instanciation d'un objet de type B, la constructeur de A puis
celui de B est appelé ?
*pA = *pB; est équivalent à *pA.operator=( *pB );
L'opérateur d'affectation appelé est donc celui qui se trouve dans la classe
Seq1, dans laquelle on se connait rien de Seq2...
Quand tu fais « *pA = *pB », tu affectes un Seq2 à un Seq1. Le compilateur résoud le surcharge en faveur de l'affectation par copie (Seq1 étant une base de Seq2), et essaie donc de générer une implémentation implicitement aussi. Et c'est là que le bat blesse -- la version générée appelle les opérateurs d'affectation des classes de base.
Pour ma part, j'ai un peu de mal à comprendre là. Si je t'ai bien suivi, le compilateur génère implicitement l'implémentation suivante: ISeq1& operator=( ISeq1 const& );
et c'est cette implémentation qui est utilisée lors du « *pA = *pB » alors pourquoi a-t-on aussi besoin de d'une implémentation de l'opérateur d'affectation dans les classes de bases ? Est-ce que c'est le même mécanisme que lorsqu'une classe B hérite d'une classe A, lors de l'instanciation d'un objet de type B, la constructeur de A puis celui de B est appelé ?
*pA = *pB; est équivalent à *pA.operator=( *pB );
L'opérateur d'affectation appelé est donc celui qui se trouve dans la classe Seq1, dans laquelle on se connait rien de Seq2...
Chris
peyrega
*pA = *pB; est équivalent à *pA.operator=( *pB );
L'opérateur d'affectation appelé est donc celui qui se trouve dans la classe Seq1, dans laquelle on se connait rien de Seq2... Chris
Au pire, Seq2 est de type Seq1 et donc l'opérateur
Seq1<T>& operator=(Seq1<T> const& obj);
défini implcitement devrait être apellé non ?
comme de plus l'opérateur ISeq<T>& operator=(ISeq<T> const& obj); est défini et virtuel, il devrait logiquement être apellé... enfin c'est ce à quoi je m'attendais -- 0% de pub! Que du bonheur et des vrais adhérents ! Vous aussi inscrivez-vous sans plus tarder!! Message posté à partir de http://www.gyptis.org, BBS actif depuis 1995.
*pA = *pB; est équivalent à *pA.operator=( *pB );
L'opérateur d'affectation appelé est donc celui qui se trouve dans la classe
Seq1, dans laquelle on se connait rien de Seq2...
Chris
Au pire, Seq2 est de type Seq1 et donc l'opérateur
Seq1<T>& operator=(Seq1<T> const& obj);
défini implcitement devrait être apellé non ?
comme de plus l'opérateur ISeq<T>& operator=(ISeq<T> const& obj);
est défini et virtuel, il devrait logiquement être apellé... enfin c'est
ce à quoi je m'attendais
--
0% de pub! Que du bonheur et des vrais adhérents !
Vous aussi inscrivez-vous sans plus tarder!!
Message posté à partir de http://www.gyptis.org, BBS actif depuis 1995.
L'opérateur d'affectation appelé est donc celui qui se trouve dans la classe Seq1, dans laquelle on se connait rien de Seq2... Chris
Au pire, Seq2 est de type Seq1 et donc l'opérateur
Seq1<T>& operator=(Seq1<T> const& obj);
défini implcitement devrait être apellé non ?
comme de plus l'opérateur ISeq<T>& operator=(ISeq<T> const& obj); est défini et virtuel, il devrait logiquement être apellé... enfin c'est ce à quoi je m'attendais -- 0% de pub! Que du bonheur et des vrais adhérents ! Vous aussi inscrivez-vous sans plus tarder!! Message posté à partir de http://www.gyptis.org, BBS actif depuis 1995.
kanze
DG wrote in message news:...
writes:
[...]
Quand tu fais « *pA = *pB », tu affectes un Seq2 à un Seq1. Le compilateur résoud le surcharge en faveur de l'affectation par copie (Seq1 étant une base de Seq2), et essaie donc de générer une implémentation implicitement aussi. Et c'est là que le bat blesse -- la version générée appelle les opérateurs d'affectation des classes de base.
Pour ma part, j'ai un peu de mal à comprendre là. Si je t'ai bien suivi, le compilateur génère implicitement l'implémentation suivante: ISeq1& operator=( ISeq1 const& );
Si l'utilisateur ne déclare pas un opérateur d'affectation à copie, le compilateur en génère implicitement une declaration. La signature de la declaration dépend en partie de la classe (ou plutôt, de ses membres et de ses bases), mais en général, c'est celle-là.
Si l'opérateur finit par servir, le compilateur génère aussi l'implémentation. L'implémentation implicite, c'est simplement d'appeler le même opérateur pour tous les membres et toutes les bases.
et c'est cette implémentation qui est utilisée lors du « *pA = *pB »
Dans ce cas-ci, oui. C'est un peu subtile, du fait que pB n'est pas un Seq1. Mais c'est quand même cet opérateur que le compilateur trouve.
alors pourquoi a-t-on aussi besoin de d'une implémentation de l'opérateur d'affectation dans les classes de bases ?
Parce que c'est ce que la version implicite appelle. Elle effectue une affectation membre à membre (et base à base).
Est-ce que c'est le même mécanisme que lorsqu'une classe B hérite d'une classe A, lors de l'instanciation d'un objet de type B, la constructeur de A puis celui de B est appelé ?
Pas tout à fait, mais prèsque. (La différence, c'est que dans le cas d'un constructeur, le compilateur s'arrange à n'appeler le constructeur qu'une fois par sous-objet, tandis que dans le cas de l'opérateur d'affectation, il fait de façon bête -- l'operator= d'une base virtuelle risque alors d'être appeler plusieurs fois.)
-- 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
DG <dany42NOSPAM@free.fr> wrote in message
news:<86isng7z2q.fsf@macphisto.homeunix.org>...
kanze@gabi-soft.fr writes:
[...]
Quand tu fais « *pA = *pB », tu affectes un Seq2 à un Seq1. Le
compilateur résoud le surcharge en faveur de l'affectation par copie
(Seq1 étant une base de Seq2), et essaie donc de générer une
implémentation implicitement aussi. Et c'est là que le bat blesse --
la version générée appelle les opérateurs d'affectation des classes
de base.
Pour ma part, j'ai un peu de mal à comprendre là. Si je t'ai bien
suivi, le compilateur génère implicitement l'implémentation suivante:
ISeq1& operator=( ISeq1 const& );
Si l'utilisateur ne déclare pas un opérateur d'affectation à copie, le
compilateur en génère implicitement une declaration. La signature de la
declaration dépend en partie de la classe (ou plutôt, de ses membres et
de ses bases), mais en général, c'est celle-là.
Si l'opérateur finit par servir, le compilateur génère aussi
l'implémentation. L'implémentation implicite, c'est simplement d'appeler
le même opérateur pour tous les membres et toutes les bases.
et c'est cette implémentation qui est utilisée lors du « *pA = *pB »
Dans ce cas-ci, oui. C'est un peu subtile, du fait que pB n'est pas un
Seq1. Mais c'est quand même cet opérateur que le compilateur trouve.
alors pourquoi a-t-on aussi besoin de d'une implémentation de
l'opérateur d'affectation dans les classes de bases ?
Parce que c'est ce que la version implicite appelle. Elle effectue une
affectation membre à membre (et base à base).
Est-ce que c'est le même mécanisme que lorsqu'une classe B hérite
d'une classe A, lors de l'instanciation d'un objet de type B, la
constructeur de A puis celui de B est appelé ?
Pas tout à fait, mais prèsque. (La différence, c'est que dans le cas
d'un constructeur, le compilateur s'arrange à n'appeler le constructeur
qu'une fois par sous-objet, tandis que dans le cas de l'opérateur
d'affectation, il fait de façon bête -- l'operator= d'une base virtuelle
risque alors d'être appeler plusieurs fois.)
--
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
Quand tu fais « *pA = *pB », tu affectes un Seq2 à un Seq1. Le compilateur résoud le surcharge en faveur de l'affectation par copie (Seq1 étant une base de Seq2), et essaie donc de générer une implémentation implicitement aussi. Et c'est là que le bat blesse -- la version générée appelle les opérateurs d'affectation des classes de base.
Pour ma part, j'ai un peu de mal à comprendre là. Si je t'ai bien suivi, le compilateur génère implicitement l'implémentation suivante: ISeq1& operator=( ISeq1 const& );
Si l'utilisateur ne déclare pas un opérateur d'affectation à copie, le compilateur en génère implicitement une declaration. La signature de la declaration dépend en partie de la classe (ou plutôt, de ses membres et de ses bases), mais en général, c'est celle-là.
Si l'opérateur finit par servir, le compilateur génère aussi l'implémentation. L'implémentation implicite, c'est simplement d'appeler le même opérateur pour tous les membres et toutes les bases.
et c'est cette implémentation qui est utilisée lors du « *pA = *pB »
Dans ce cas-ci, oui. C'est un peu subtile, du fait que pB n'est pas un Seq1. Mais c'est quand même cet opérateur que le compilateur trouve.
alors pourquoi a-t-on aussi besoin de d'une implémentation de l'opérateur d'affectation dans les classes de bases ?
Parce que c'est ce que la version implicite appelle. Elle effectue une affectation membre à membre (et base à base).
Est-ce que c'est le même mécanisme que lorsqu'une classe B hérite d'une classe A, lors de l'instanciation d'un objet de type B, la constructeur de A puis celui de B est appelé ?
Pas tout à fait, mais prèsque. (La différence, c'est que dans le cas d'un constructeur, le compilateur s'arrange à n'appeler le constructeur qu'une fois par sous-objet, tandis que dans le cas de l'opérateur d'affectation, il fait de façon bête -- l'operator= d'une base virtuelle risque alors d'être appeler plusieurs fois.)
-- 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
kanze
Christophe de Vienne wrote in message news:<newscache$8bdtlh$j38$...
Mathieu Peyréga wrote:
Bonsoir, que ce soit avec VC++ ou gcc, le code suivant ne compile pas (ou plus exactement ne linke pas...)
Pourrais-tu être plus précis : quels sont les messages du linker ?
Je crois qu'il voulait qu'on joue aux dévinettes.
En revanche, j'ai bien apprécié le fait qu'il a posté un exemple complet, et non un petit extrait. Ça manque, parfois, et cette fois-ci, le problème n'est pas où on aurait tendance à le chercher.
-- 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
Christophe de Vienne <cdevienne@alphacent.com> wrote in message
news:<newscache$8bdtlh$j38$1@guronzan.alphacent.com>...
Mathieu Peyréga wrote:
Bonsoir, que ce soit avec VC++ ou gcc, le code suivant ne compile
pas (ou plus exactement ne linke pas...)
Pourrais-tu être plus précis : quels sont les messages du linker ?
Je crois qu'il voulait qu'on joue aux dévinettes.
En revanche, j'ai bien apprécié le fait qu'il a posté un exemple
complet, et non un petit extrait. Ça manque, parfois, et cette fois-ci,
le problème n'est pas où on aurait tendance à le chercher.
--
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
Christophe de Vienne wrote in message news:<newscache$8bdtlh$j38$...
Mathieu Peyréga wrote:
Bonsoir, que ce soit avec VC++ ou gcc, le code suivant ne compile pas (ou plus exactement ne linke pas...)
Pourrais-tu être plus précis : quels sont les messages du linker ?
Je crois qu'il voulait qu'on joue aux dévinettes.
En revanche, j'ai bien apprécié le fait qu'il a posté un exemple complet, et non un petit extrait. Ça manque, parfois, et cette fois-ci, le problème n'est pas où on aurait tendance à le chercher.
-- 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
DG
writes:
DG wrote in message news:...
writes:
[...]
Pour ma part, j'ai un peu de mal à comprendre là. Si je t'ai bien suivi, le compilateur génère implicitement l'implémentation suivante: ISeq1& operator=( ISeq1 const& );
Si l'utilisateur ne déclare pas un opérateur d'affectation à copie, le compilateur en génère implicitement une declaration. La signature de la declaration dépend en partie de la classe (ou plutôt, de ses membres et de ses bases), mais en général, c'est celle-là.
Si l'opérateur finit par servir, le compilateur génère aussi l'implémentation. L'implémentation implicite, c'est simplement d'appeler le même opérateur pour tous les membres et toutes les bases.
et c'est cette implémentation qui est utilisée lors du « *pA = *pB »
Dans ce cas-ci, oui. C'est un peu subtile, du fait que pB n'est pas un Seq1. Mais c'est quand même cet opérateur que le compilateur trouve.
alors pourquoi a-t-on aussi besoin de d'une implémentation de l'opérateur d'affectation dans les classes de bases ?
Parce que c'est ce que la version implicite appelle. Elle effectue une affectation membre à membre (et base à base).
Est-ce que c'est le même mécanisme que lorsqu'une classe B hérite d'une classe A, lors de l'instanciation d'un objet de type B, la constructeur de A puis celui de B est appelé ?
Pas tout à fait, mais prèsque. (La différence, c'est que dans le cas d'un constructeur, le compilateur s'arrange à n'appeler le constructeur qu'une fois par sous-objet, tandis que dans le cas de l'opérateur d'affectation, il fait de façon bête -- l'operator= d'une base virtuelle risque alors d'être appeler plusieurs fois.)
Merci pour tes explications ; je comprend un peu mieux le problème maintenant. En fait, je ne savais pas que la version implicite effectuait une affectation de base à base...
kanze@gabi-soft.fr writes:
DG <dany42NOSPAM@free.fr> wrote in message
news:<86isng7z2q.fsf@macphisto.homeunix.org>...
kanze@gabi-soft.fr writes:
[...]
Pour ma part, j'ai un peu de mal à comprendre là. Si je t'ai bien
suivi, le compilateur génère implicitement l'implémentation suivante:
ISeq1& operator=( ISeq1 const& );
Si l'utilisateur ne déclare pas un opérateur d'affectation à copie, le
compilateur en génère implicitement une declaration. La signature de la
declaration dépend en partie de la classe (ou plutôt, de ses membres et
de ses bases), mais en général, c'est celle-là.
Si l'opérateur finit par servir, le compilateur génère aussi
l'implémentation. L'implémentation implicite, c'est simplement d'appeler
le même opérateur pour tous les membres et toutes les bases.
et c'est cette implémentation qui est utilisée lors du « *pA = *pB »
Dans ce cas-ci, oui. C'est un peu subtile, du fait que pB n'est pas un
Seq1. Mais c'est quand même cet opérateur que le compilateur trouve.
alors pourquoi a-t-on aussi besoin de d'une implémentation de
l'opérateur d'affectation dans les classes de bases ?
Parce que c'est ce que la version implicite appelle. Elle effectue une
affectation membre à membre (et base à base).
Est-ce que c'est le même mécanisme que lorsqu'une classe B hérite
d'une classe A, lors de l'instanciation d'un objet de type B, la
constructeur de A puis celui de B est appelé ?
Pas tout à fait, mais prèsque. (La différence, c'est que dans le cas
d'un constructeur, le compilateur s'arrange à n'appeler le constructeur
qu'une fois par sous-objet, tandis que dans le cas de l'opérateur
d'affectation, il fait de façon bête -- l'operator= d'une base virtuelle
risque alors d'être appeler plusieurs fois.)
Merci pour tes explications ; je comprend un peu mieux le problème
maintenant. En fait, je ne savais pas que la version implicite
effectuait une affectation de base à base...
Pour ma part, j'ai un peu de mal à comprendre là. Si je t'ai bien suivi, le compilateur génère implicitement l'implémentation suivante: ISeq1& operator=( ISeq1 const& );
Si l'utilisateur ne déclare pas un opérateur d'affectation à copie, le compilateur en génère implicitement une declaration. La signature de la declaration dépend en partie de la classe (ou plutôt, de ses membres et de ses bases), mais en général, c'est celle-là.
Si l'opérateur finit par servir, le compilateur génère aussi l'implémentation. L'implémentation implicite, c'est simplement d'appeler le même opérateur pour tous les membres et toutes les bases.
et c'est cette implémentation qui est utilisée lors du « *pA = *pB »
Dans ce cas-ci, oui. C'est un peu subtile, du fait que pB n'est pas un Seq1. Mais c'est quand même cet opérateur que le compilateur trouve.
alors pourquoi a-t-on aussi besoin de d'une implémentation de l'opérateur d'affectation dans les classes de bases ?
Parce que c'est ce que la version implicite appelle. Elle effectue une affectation membre à membre (et base à base).
Est-ce que c'est le même mécanisme que lorsqu'une classe B hérite d'une classe A, lors de l'instanciation d'un objet de type B, la constructeur de A puis celui de B est appelé ?
Pas tout à fait, mais prèsque. (La différence, c'est que dans le cas d'un constructeur, le compilateur s'arrange à n'appeler le constructeur qu'une fois par sous-objet, tandis que dans le cas de l'opérateur d'affectation, il fait de façon bête -- l'operator= d'une base virtuelle risque alors d'être appeler plusieurs fois.)
Merci pour tes explications ; je comprend un peu mieux le problème maintenant. En fait, je ne savais pas que la version implicite effectuait une affectation de base à base...
Laurent DELEPINE
Jean-Marc Bourguet wrote:
Rien n'empeche de definir un membre pur, c'est meme obligatoire pour le destructeur.
Jusqu'a present, je trouvais mon bouquin de C++ incomprehensible, maintenant je decouvre qu'il est faux. Genial.
Heureusement, faire du feu devrait bientot etre autorisé ici.
A+
LD
Jean-Marc Bourguet wrote:
Rien n'empeche de definir un membre pur, c'est meme obligatoire pour
le destructeur.
Jusqu'a present, je trouvais mon bouquin de C++ incomprehensible,
maintenant je decouvre qu'il est faux. Genial.
Heureusement, faire du feu devrait bientot etre autorisé ici.
Rien n'empeche de definir un membre pur, c'est meme obligatoire pour le destructeur.
Jusqu'a present, je trouvais mon bouquin de C++ incomprehensible, maintenant je decouvre qu'il est faux. Genial.
Heureusement, faire du feu devrait bientot etre autorisé ici.
A+
LD
James Kanze
"Christophe Lephay" writes:
|> "DG" a écrit dans le message de |> news: |> > writes: |> > > Quand tu fais « *pA = *pB », tu affectes un Seq2 à un |> > > Seq1. Le compilateur résoud le surcharge en faveur de |> > > l'affectation par copie (Seq1 étant une base de Seq2), et |> > > essaie donc de générer une implémentation implicitement |> > > aussi. Et c'est là que le bat blesse -- la version |> > > générée appelle les opérateurs d'affectation des |> > > classes de base.
|> > Pour ma part, j'ai un peu de mal à comprendre là. Si je t'ai |> > bien suivi, le compilateur génère implicitement |> > l'implémentation suivante: ISeq1& operator=( ISeq1 const& );
|> > et c'est cette implémentation qui est utilisée lors du « |> > *pA = *pB » alors pourquoi a-t-on aussi besoin de d'une |> > implémentation de l'opérateur d'affectation dans les classes |> > de bases ? Est-ce que c'est le même mécanisme que lorsqu'une |> > classe B hérite d'une classe A, lors de l'instanciation d'un |> > objet de type B, la constructeur de A puis celui de B est |> > appelé ?
|> *pA = *pB; est équivalent à *pA.operator=( *pB );
En effet.
|> L'opérateur d'affectation appelé est donc celui qui se trouve |> dans la classe Seq1, dans laquelle on se connait rien de Seq2...
L'opérateur d'affectation appelé est un des *deux* qui se trouve dans la classe Seq1. Il y a donc résolution du surcharge.
Je crois que le problème vient du fait que le posteur original ne s'est pas rendu compte qu'il y avait deux opérateurs d'affectation en jeu, étant donné qu'il n'en a écrit qu'un.
-- James Kanze mailto: Conseils en informatique orientée objet/ Beratung in objektorientierter Datenverarbeitung 11 rue de Rambouillet, 78460 Chevreuse, France +33 1 41 89 80 93
|> "DG" <dany42NOSPAM@free.fr> a écrit dans le message de
|> news:86isng7z2q.fsf@macphisto.homeunix.org...
|> > kanze@gabi-soft.fr writes:
|> > > Quand tu fais « *pA = *pB », tu affectes un Seq2 à un
|> > > Seq1. Le compilateur résoud le surcharge en faveur de
|> > > l'affectation par copie (Seq1 étant une base de Seq2), et
|> > > essaie donc de générer une implémentation implicitement
|> > > aussi. Et c'est là que le bat blesse -- la version
|> > > générée appelle les opérateurs d'affectation des
|> > > classes de base.
|> > Pour ma part, j'ai un peu de mal à comprendre là. Si je t'ai
|> > bien suivi, le compilateur génère implicitement
|> > l'implémentation suivante: ISeq1& operator=( ISeq1 const& );
|> > et c'est cette implémentation qui est utilisée lors du «
|> > *pA = *pB » alors pourquoi a-t-on aussi besoin de d'une
|> > implémentation de l'opérateur d'affectation dans les classes
|> > de bases ? Est-ce que c'est le même mécanisme que lorsqu'une
|> > classe B hérite d'une classe A, lors de l'instanciation d'un
|> > objet de type B, la constructeur de A puis celui de B est
|> > appelé ?
|> *pA = *pB; est équivalent à *pA.operator=( *pB );
En effet.
|> L'opérateur d'affectation appelé est donc celui qui se trouve
|> dans la classe Seq1, dans laquelle on se connait rien de Seq2...
L'opérateur d'affectation appelé est un des *deux* qui se trouve
dans la classe Seq1. Il y a donc résolution du surcharge.
Je crois que le problème vient du fait que le posteur original ne
s'est pas rendu compte qu'il y avait deux opérateurs d'affectation en
jeu, étant donné qu'il n'en a écrit qu'un.
--
James Kanze mailto:kanze@gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France +33 1 41 89 80 93
|> "DG" a écrit dans le message de |> news: |> > writes: |> > > Quand tu fais « *pA = *pB », tu affectes un Seq2 à un |> > > Seq1. Le compilateur résoud le surcharge en faveur de |> > > l'affectation par copie (Seq1 étant une base de Seq2), et |> > > essaie donc de générer une implémentation implicitement |> > > aussi. Et c'est là que le bat blesse -- la version |> > > générée appelle les opérateurs d'affectation des |> > > classes de base.
|> > Pour ma part, j'ai un peu de mal à comprendre là. Si je t'ai |> > bien suivi, le compilateur génère implicitement |> > l'implémentation suivante: ISeq1& operator=( ISeq1 const& );
|> > et c'est cette implémentation qui est utilisée lors du « |> > *pA = *pB » alors pourquoi a-t-on aussi besoin de d'une |> > implémentation de l'opérateur d'affectation dans les classes |> > de bases ? Est-ce que c'est le même mécanisme que lorsqu'une |> > classe B hérite d'une classe A, lors de l'instanciation d'un |> > objet de type B, la constructeur de A puis celui de B est |> > appelé ?
|> *pA = *pB; est équivalent à *pA.operator=( *pB );
En effet.
|> L'opérateur d'affectation appelé est donc celui qui se trouve |> dans la classe Seq1, dans laquelle on se connait rien de Seq2...
L'opérateur d'affectation appelé est un des *deux* qui se trouve dans la classe Seq1. Il y a donc résolution du surcharge.
Je crois que le problème vient du fait que le posteur original ne s'est pas rendu compte qu'il y avait deux opérateurs d'affectation en jeu, étant donné qu'il n'en a écrit qu'un.
-- James Kanze mailto: Conseils en informatique orientée objet/ Beratung in objektorientierter Datenverarbeitung 11 rue de Rambouillet, 78460 Chevreuse, France +33 1 41 89 80 93
James Kanze
(Mathieu Peyréga) writes:
|> > *pA = *pB; est équivalent à *pA.operator=( *pB );
|> > L'opérateur d'affectation appelé est donc celui qui se |> > trouve dans la classe Seq1, dans laquelle on se connait rien de |> > Seq2...
|> Au pire, Seq2 est de type Seq1 et donc l'opérateur
|> Seq1<T>& operator=(Seq1<T> const& obj);
|> défini implcitement devrait être apellé non ?
En effet.
|> comme de plus l'opérateur ISeq<T>& operator=(ISeq<T> const& obj); |> est défini et virtuel, il devrait logiquement être |> apellé... enfin c'est ce à quoi je m'attendais
Il y a résolution du surcharge des deux opérateurs : celui écrit par l'utilisateur, celui implicit. Dans ce cas-ci, il s'avère que c'est celui implicit qui gagne.
Une règle simple, qui empeche des surprises : chaque fois que tu fournis un opérateur d'affectation qui n'est PAS une affectation de copie, c-à-d dont le paramètre n'est pas une référence à la classe même, fournis aussi une affectation de copie, qui fait ce que tu veux.
Ma propre solution, quand il s'agit d'une hièrarchie, ET que je voulais quand même supporter l'affectation (qui est, comme j'ai dit par ailleurs, extrèmement rare), j'utilise une fonction virtuelle assign, puis je fournis les operator= qui l'appellent. Et dès que la classe hérite, je fournis au moins deux operator= :
Derived& Derived::operator=( Derived const& other ) { assign( other ) ; return *this ; }
Base& Derived::operator=( Base const& ) { assign( other ) ; return *this ; }
(ou Base, c'est bien la base de l'hièrarchie).
-- James Kanze mailto: Conseils en informatique orientée objet/ Beratung in objektorientierter Datenverarbeitung 11 rue de Rambouillet, 78460 Chevreuse, France +33 1 41 89 80 93
peyrega@netcourrier.com (Mathieu Peyréga) writes:
|> > *pA = *pB; est équivalent à *pA.operator=( *pB );
|> > L'opérateur d'affectation appelé est donc celui qui se
|> > trouve dans la classe Seq1, dans laquelle on se connait rien de
|> > Seq2...
|> Au pire, Seq2 est de type Seq1 et donc l'opérateur
|> Seq1<T>& operator=(Seq1<T> const& obj);
|> défini implcitement devrait être apellé non ?
En effet.
|> comme de plus l'opérateur ISeq<T>& operator=(ISeq<T> const& obj);
|> est défini et virtuel, il devrait logiquement être
|> apellé... enfin c'est ce à quoi je m'attendais
Il y a résolution du surcharge des deux opérateurs : celui
écrit par l'utilisateur, celui implicit. Dans ce cas-ci, il
s'avère que c'est celui implicit qui gagne.
Une règle simple, qui empeche des surprises : chaque fois que tu
fournis un opérateur d'affectation qui n'est PAS une affectation de
copie, c-à-d dont le paramètre n'est pas une référence à
la classe même, fournis aussi une affectation de copie, qui fait ce
que tu veux.
Ma propre solution, quand il s'agit d'une hièrarchie, ET que je
voulais quand même supporter l'affectation (qui est, comme j'ai dit
par ailleurs, extrèmement rare), j'utilise une fonction virtuelle
assign, puis je fournis les operator= qui l'appellent. Et dès que la
classe hérite, je fournis au moins deux operator= :
Derived&
Derived::operator=( Derived const& other )
{
assign( other ) ;
return *this ;
}
Base& Derived::operator=( Base const& )
{
assign( other ) ;
return *this ;
}
(ou Base, c'est bien la base de l'hièrarchie).
--
James Kanze mailto:kanze@gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France +33 1 41 89 80 93
|> > *pA = *pB; est équivalent à *pA.operator=( *pB );
|> > L'opérateur d'affectation appelé est donc celui qui se |> > trouve dans la classe Seq1, dans laquelle on se connait rien de |> > Seq2...
|> Au pire, Seq2 est de type Seq1 et donc l'opérateur
|> Seq1<T>& operator=(Seq1<T> const& obj);
|> défini implcitement devrait être apellé non ?
En effet.
|> comme de plus l'opérateur ISeq<T>& operator=(ISeq<T> const& obj); |> est défini et virtuel, il devrait logiquement être |> apellé... enfin c'est ce à quoi je m'attendais
Il y a résolution du surcharge des deux opérateurs : celui écrit par l'utilisateur, celui implicit. Dans ce cas-ci, il s'avère que c'est celui implicit qui gagne.
Une règle simple, qui empeche des surprises : chaque fois que tu fournis un opérateur d'affectation qui n'est PAS une affectation de copie, c-à-d dont le paramètre n'est pas une référence à la classe même, fournis aussi une affectation de copie, qui fait ce que tu veux.
Ma propre solution, quand il s'agit d'une hièrarchie, ET que je voulais quand même supporter l'affectation (qui est, comme j'ai dit par ailleurs, extrèmement rare), j'utilise une fonction virtuelle assign, puis je fournis les operator= qui l'appellent. Et dès que la classe hérite, je fournis au moins deux operator= :
Derived& Derived::operator=( Derived const& other ) { assign( other ) ; return *this ; }
Base& Derived::operator=( Base const& ) { assign( other ) ; return *this ; }
(ou Base, c'est bien la base de l'hièrarchie).
-- James Kanze mailto: Conseils en informatique orientée objet/ Beratung in objektorientierter Datenverarbeitung 11 rue de Rambouillet, 78460 Chevreuse, France +33 1 41 89 80 93
James Kanze
(Mathieu Peyréga) writes:
|> > Enfin, un commentaire plus général : la virtualité et |> > l'affectation font mauvais menage. En fait, on ne peut pas changer |> > le type de l'objet dans l'affectation. Le plus souvent, on |> > préfère donc ne travailler qu'avec des pointeurs, et |> > d'utiliser une fonction « clone »
|> ça pour faire mauvais ménage...
Le problème, c'est bien si je fais quelque chose du genre :
Base *pA = new Derived1 ; Base *pB = new Derived2 ;
*pA = *pB ;
Après l'affectation, *pA est toujours un Derived1. Alors, la question est : comment définir l'affectation pour que ça a un sens ?
Il y a des exceptions, où par exemple la base est une classe du genre PersistentObject. En revanche, dans ces cas, on ne veut pas en général supporter l'affectation entre deux PersistentObject ; on déclare donc l'opérateur d'affectation protégé, voire même privée (ce qui oblige les classes dérivées à le declarer explicitement si elles veulent le supporter).
J'ai aussi vu des cas où l'opérateur d'affectation dans la classe de base commençait par : assert( typeid( *this ) == typeid( other ) ) ; Je suppose qu'il y a des cas où ça peut être utile, même si j'ai du mal à les imaginer.
Enfin, quand on veut vraiment donner une sémantique de valeur à des objets polymorphiques, il y a le modèle lettre-envellope de Coplien.
Et quand au ménage, il y a des pointeurs intelligents : Scott Meyers présentent un qui est assez semblable à celui sur ma site, et Barton et Nackman présente un qui ressemble à celui de Boost (mais Boost l'a fait beaucoup évolué).
-- James Kanze mailto: Conseils en informatique orientée objet/ Beratung in objektorientierter Datenverarbeitung 11 rue de Rambouillet, 78460 Chevreuse, France +33 1 41 89 80 93
peyrega@netcourrier.com (Mathieu Peyréga) writes:
|> > Enfin, un commentaire plus général : la virtualité et
|> > l'affectation font mauvais menage. En fait, on ne peut pas changer
|> > le type de l'objet dans l'affectation. Le plus souvent, on
|> > préfère donc ne travailler qu'avec des pointeurs, et
|> > d'utiliser une fonction « clone »
|> ça pour faire mauvais ménage...
Le problème, c'est bien si je fais quelque chose du genre :
Base *pA = new Derived1 ;
Base *pB = new Derived2 ;
*pA = *pB ;
Après l'affectation, *pA est toujours un Derived1. Alors, la question
est : comment définir l'affectation pour que ça a un sens ?
Il y a des exceptions, où par exemple la base est une classe du genre
PersistentObject. En revanche, dans ces cas, on ne veut pas en
général supporter l'affectation entre deux PersistentObject ; on
déclare donc l'opérateur d'affectation protégé, voire
même privée (ce qui oblige les classes dérivées à le
declarer explicitement si elles veulent le supporter).
J'ai aussi vu des cas où l'opérateur d'affectation dans la classe
de base commençait par :
assert( typeid( *this ) == typeid( other ) ) ;
Je suppose qu'il y a des cas où ça peut être utile, même si
j'ai du mal à les imaginer.
Enfin, quand on veut vraiment donner une sémantique de valeur à
des objets polymorphiques, il y a le modèle lettre-envellope de
Coplien.
Et quand au ménage, il y a des pointeurs intelligents : Scott Meyers
présentent un qui est assez semblable à celui sur ma site, et
Barton et Nackman présente un qui ressemble à celui de Boost (mais
Boost l'a fait beaucoup évolué).
--
James Kanze mailto:kanze@gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France +33 1 41 89 80 93
|> > Enfin, un commentaire plus général : la virtualité et |> > l'affectation font mauvais menage. En fait, on ne peut pas changer |> > le type de l'objet dans l'affectation. Le plus souvent, on |> > préfère donc ne travailler qu'avec des pointeurs, et |> > d'utiliser une fonction « clone »
|> ça pour faire mauvais ménage...
Le problème, c'est bien si je fais quelque chose du genre :
Base *pA = new Derived1 ; Base *pB = new Derived2 ;
*pA = *pB ;
Après l'affectation, *pA est toujours un Derived1. Alors, la question est : comment définir l'affectation pour que ça a un sens ?
Il y a des exceptions, où par exemple la base est une classe du genre PersistentObject. En revanche, dans ces cas, on ne veut pas en général supporter l'affectation entre deux PersistentObject ; on déclare donc l'opérateur d'affectation protégé, voire même privée (ce qui oblige les classes dérivées à le declarer explicitement si elles veulent le supporter).
J'ai aussi vu des cas où l'opérateur d'affectation dans la classe de base commençait par : assert( typeid( *this ) == typeid( other ) ) ; Je suppose qu'il y a des cas où ça peut être utile, même si j'ai du mal à les imaginer.
Enfin, quand on veut vraiment donner une sémantique de valeur à des objets polymorphiques, il y a le modèle lettre-envellope de Coplien.
Et quand au ménage, il y a des pointeurs intelligents : Scott Meyers présentent un qui est assez semblable à celui sur ma site, et Barton et Nackman présente un qui ressemble à celui de Boost (mais Boost l'a fait beaucoup évolué).
-- James Kanze mailto: Conseils en informatique orientée objet/ Beratung in objektorientierter Datenverarbeitung 11 rue de Rambouillet, 78460 Chevreuse, France +33 1 41 89 80 93