C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Problème d'héritage
Goto page 1, 2  Next
 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ (French)
View previous topic :: View next topic  
Author Message
Philip K. Dick
Guest





PostPosted: Wed Mar 28, 2007 9:35 pm    Post subject: Problème d'héritage Reply with quote



Hello

J'ai une classe Point :

class Point {
public:
Point(int x=0, int y=0);
Point(const Point & p);
Point & operator = (const Point & p);
~Point();
Point symetric ();
protected:
int x;
int y;
};
dont la méthode symetric() retourne un Point de coordonnées (-x,-y)

La classe Pixel en hérite (avec un attribut couleur en plus)
et définit aussi symetric() qui retourne un Pixel :

class Pixel : public Point {
public:
Pixel(int x=0, int y=0, short color=0);
Pixel(const Pixel & p);
Pixel & operator = (const Pixel & p);
~Pixel();
Pixel symetric ();
protected:
short color;
};

Je voudrais écrire Pixel::symetric en réutilisant Point::symetric.
J'avais écrit :

Pixel::Pixel Pixel::symetric () {
Point p = this->Point::symetric();
Pixel q (p.x, p.y, this->color);
return q;
};

mais :
1) ça n'a pas l'air très économique (j'aurais aimé utiliser Point::symetric() sur un Pixel)
2) Le compilateur me jette, il ne veut pas de p.x ou p.y,
pourtant les attributs x et y sont protected ???
pixel.cc: In method `class Heritage::Pixel Heritage::Pixel::symetric()':
point.h:17: `int Heritage::Point:Mad' is protected
pixel.cc:27: within this context

Une idée ?

PKD
Back to top
alex
Guest





PostPosted: Wed Mar 28, 2007 11:04 pm    Post subject: Re: Problème d'héritage Reply with quote



salut,

Quote:
Pixel::Pixel Pixel::symetric () {
Point p = this->Point::symetric();
Pixel q (p.x, p.y, this->color);
return q;
};

j'aurais quant à moi écrit un constructeur de pixel à partir d'un point et
d'un color, ce qui donnerait :

Pixel Pixel::symetric()
{
return Pixel(Point::symetric(), color);
}

en passant, j'aurais défini cette fonction const.
Quote:


1) ça n'a pas l'air très économique (j'aurais aimé utiliser
Point::symetric() sur un Pixel)

rien ne t'en empeche, mais Point::symetric() renverra toujours un point...
Si tu veux que Point::symetric() puisse servir à un Pixel, tu peux la
définir comme :

void Point::symetric()
{
x = -x;
y = -y;
}

Comme ça, tu n'as pas besoin de la définir dans Pixel (si color ne change
pas) et tu n'as pas besoin d'accéder à x et y dans les classes dérivées. (de
manière générale, les attributs devraient être privés, et non protected. Si
tu as besoin des attributs de l'ancêtre dans le descendant, ça indique
souvent une erreur de conception.)
Back to top
Philip K Dick
Guest





PostPosted: Thu Mar 29, 2007 12:16 am    Post subject: Re: Problème d'héritage Reply with quote



alex a écrit :
Quote:
salut,

Pixel::Pixel Pixel::symetric () {
Point p = this->Point::symetric();
Pixel q (p.x, p.y, this->color);
return q;
};

j'aurais quant à moi écrit un constructeur de pixel à partir d'un point et
d'un color, ce qui donnerait :

Pixel Pixel::symetric()
{
return Pixel(Point::symetric(), color);
}

en passant, j'aurais défini cette fonction const.

Merci Alex pour ta réponse. Effectivement, c'est mieux
que ce que j'avais fait :-)

Quote:
1) ça n'a pas l'air très économique (j'aurais aimé utiliser
Point::symetric() sur un Pixel)

rien ne t'en empeche, mais Point::symetric() renverra toujours un point...
Si tu veux que Point::symetric() puisse servir à un Pixel, tu peux la
définir comme :

void Point::symetric()
{
x = -x;
y = -y;
}

Comme ça, tu n'as pas besoin de la définir dans Pixel (si color ne change
pas) et tu n'as pas besoin d'accéder à x et y dans les classes dérivées.

Par contre, ça ne fais pas ce que je voulais car ça change les attributs
de l'objet.

(de manière générale, les attributs devraient être privés, et non
protected. Si
Quote:
tu as besoin des attributs de l'ancêtre dans le descendant, ça indique
souvent une erreur de conception.)

Peux-tu m'expliquer en quoi cela indique une erreur de conception ?
Perso, j'ai le Delannoy comme bouquin de C++ et nulle part je n'ai
lu ça (alors que le Stroustrup le dit, il est vrai, mais j'aimerais
comprendre).
Back to top
James Kanze
Guest





PostPosted: Thu Mar 29, 2007 9:11 am    Post subject: Re: Problème d'héritage Reply with quote

On Mar 28, 6:35 pm, "Philip K. Dick" <philip.k.d...@tele2.fr> wrote:

Quote:
J'ai une classe Point :

class Point {
public:
Point(int x=0, int y=0);
Point(const Point & p);
Point & operator = (const Point & p);
~Point();
Point symetric ();
protected:
int x;
int y;
};
dont la méthode symetric() retourne un Point de coordonnées (-x,-y)

La classe Pixel en hérite (avec un attribut couleur en plus)

Est-ce réelement ce que tu veux, de pouvoir utiliser des Pixel
partout où tu utilises des Point ? Je ne connais pas ton
application, mais très souvent, c'est plutôt l'encapsulation
qu'on veut : que Pixel contient un Point. Sinon...

Quote:
et définit aussi symetric() qui retourne un Pixel :

class Pixel : public Point {
public:
Pixel(int x=0, int y=0, short color=0);
Pixel(const Pixel & p);
Pixel & operator = (const Pixel & p);
~Pixel();
Pixel symetric ();
protected:
short color;
};

Je voudrais écrire Pixel::symetric en réutilisant Point::symetric.
J'avais écrit :

Pixel::Pixel Pixel::symetric () {
Point p = this->Point::symetric();
Pixel q (p.x, p.y, this->color);
return q;
};

mais :
1) ça n'a pas l'air très économique (j'aurais aimé utiliser Point::symetric() sur un Pixel)

Dans la mesure où la fonction renvoie un objet (ce qui me semble
une bonne idée en générale -- je n'aime pas les objets qui
change de valeur en dessous de moi), tu ne peux pas.
Point::symetric() renverra toujous un Point, jamais un Pixel.

Je crois que la suggestion d'Alex est la bonne : que le
constructeur de Pixel prend un Point, et non x et y.
Pixel::symetric() devient alors simplement :

return Pixel( Point::symetric(), color ) ;

Quote:
2) Le compilateur me jette, il ne veut pas de p.x ou p.y,
pourtant les attributs x et y sont protected ???
pixel.cc: In method `class Heritage::Pixel Heritage::Pixel::symetric()':
point.h:17: `int Heritage::Point:Mad' is protected
pixel.cc:27: within this context

C'est la règle. Protected permet l'accès dans une classe dérivée
aux éléments de la classe de base seulement si l'objet est de la
même classe (ou d'une classe dérivée) que celle qui fait
l'accès.

--
James Kanze (GABI Software) email:james.kanze (AT) gmail (DOT) com
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
Back to top
alex
Guest





PostPosted: Thu Mar 29, 2007 11:35 pm    Post subject: Re: Problème d'héritage Reply with quote

bonjour,
Quote:
(de manière générale, les attributs devraient être privés, et non
protected. Si
tu as besoin des attributs de l'ancêtre dans le descendant, ça indique
souvent une erreur de conception.)

Peux-tu m'expliquer en quoi cela indique une erreur de conception ?
Perso, j'ai le Delannoy comme bouquin de C++ et nulle part je n'ai
lu ça (alors que le Stroustrup le dit, il est vrai, mais j'aimerais
comprendre).

protected ne protège pas vraiment : il suffit d'hériter en mode public et
hop, tu as accès aux attributs. Pouvoir s'en servir correctement suppose une
connaissance précise de l'implémentation de la classe, connaissance que l'on
a rarement. En général, les attributs sont donc privés. Les méthodes
virtuelles souvent aussi, même si ce n'est pas une règle d'or gravée dans le
marbre Wink . Les membres protected sont souvent des fonctions à mi-chemin
entre le "bas" et le "haut" niveau , genre utilitaire pour l'objet, qui doit
conserver son sens même dans une classe dérivée puisqu'il sera accessible.
Back to top
Loïc Joly
Guest





PostPosted: Fri Mar 30, 2007 2:06 am    Post subject: Re: Problème d'héritage Reply with quote

alex a écrit :
Quote:
Les membres protected sont souvent des fonctions à mi-chemin
entre le "bas" et le "haut" niveau , genre utilitaire pour l'objet, qui doit
conserver son sens même dans une classe dérivée puisqu'il sera accessible.


Un cas classique, c'est celui où l'implémentation de la classe la plus
dérivée a besoin d'appeler l'implémentation de la classe juste au
dessus, qui elle même... jusqu'à la classe de base. C'est très courant
par exemple pour sérialiser ou afficher une classe.

--
Loïc
Back to top
Philip K. Dick
Guest





PostPosted: Fri Mar 30, 2007 2:40 pm    Post subject: Re: Problème d'héritage Reply with quote

Loïc Joly wrote:
Quote:
alex a écrit :
Les membres protected sont souvent des fonctions à mi-chemin entre le
"bas" et le "haut" niveau , genre utilitaire pour l'objet, qui doit
conserver son sens même dans une classe dérivée puisqu'il sera
accessible.


Un cas classique, c'est celui où l'implémentation de la classe la plus
dérivée a besoin d'appeler l'implémentation de la classe juste au
dessus, qui elle même... jusqu'à la classe de base. C'est très courant
par exemple pour sérialiser ou afficher une classe.

OK, mais dans l'exemple :

class Point {
public:
(...)
virtual afficher ();
protected:
int x;
int y;
};

class Pixel : public Point {
public:
(...)
afficher ();
protected:
short color;
};

Je souhaite que Point affiche par exemple : "(x,y)"
et que Pixel affiche "(x,y,color)".
Si x et y sont privés, je suis obligé de définir
des accesseurs (get_x(), get_y()) appelés dans la
classe dérivée.

C'est un peu lourd, non ?

PKD
Back to top
Philip K. Dick
Guest





PostPosted: Fri Mar 30, 2007 2:40 pm    Post subject: Re: Problème d'héritage Reply with quote

Loïc Joly wrote:
Quote:
alex a écrit :
Les membres protected sont souvent des fonctions à mi-chemin entre le
"bas" et le "haut" niveau , genre utilitaire pour l'objet, qui doit
conserver son sens même dans une classe dérivée puisqu'il sera
accessible.


Un cas classique, c'est celui où l'implémentation de la classe la plus
dérivée a besoin d'appeler l'implémentation de la classe juste au
dessus, qui elle même... jusqu'à la classe de base. C'est très courant
par exemple pour sérialiser ou afficher une classe.

OK, mais dans l'exemple :

class Point {
public:
(...)
virtual afficher ();
protected:
int x;
int y;
};

class Pixel : public Point {
public:
(...)
afficher ();
protected:
short color;
};

Je souhaite que Point affiche par exemple : "(x,y)"
et que Pixel affiche "(x,y,color)".
Si x et y sont privés, je suis obligé de définir
des accesseurs (get_x(), get_y()) appelés dans la
classe dérivée.

C'est un peu lourd, non ?

PKD
Back to top
alexandre
Guest





PostPosted: Fri Mar 30, 2007 4:19 pm    Post subject: Re: Problème d'héritage Reply with quote

bonjour,

Quote:
OK, mais dans l'exemple :

class Point {
public:
(...)
virtual afficher ();
protected:
int x;
int y;
};

class Pixel : public Point {
public:
(...)
afficher ();
protected:
short color;
};

Je souhaite que Point affiche par exemple : "(x,y)"
et que Pixel affiche "(x,y,color)".
Si x et y sont privés, je suis obligé de définir
des accesseurs (get_x(), get_y()) appelés dans la
classe dérivée.

C'est un peu lourd, non ?

non, tu peux mieux faire :


class Point {
public:
(...)
void afficher () const
{
std::cout<<'(';
afficheravant(); // c'est une "porte d'entrée"
std::cout<<x<<','<<y;
afficherapres(); // la aussi
std::cout<<')';
}
private:
virtual void afficheravant() const{}
virtual void afficherapres() const {}
int x;
int y;
};

class Pixel : public Point {
public:
private:
short color;
void afficherapres() const
{
std::cout<<','<<color;
}
};
Back to top
Sylvain
Guest





PostPosted: Sun Apr 01, 2007 2:30 am    Post subject: Re: Problème d'héritage Reply with quote

James Kanze wrote on 29/03/2007 09:12:
Quote:

2) Le compilateur me jette, il ne veut pas de p.x ou p.y,
pourtant les attributs x et y sont protected ???

C'est la règle. Protected permet l'accès dans une classe dérivée
aux éléments de la classe de base seulement /si l'objet est de
la même classe (ou d'une classe dérivée) que celle qui fait
l'accès./

la classe (d'objet) qui manipule les champs hérités est nécessairement
de la "même classe ou dérivée" que celle (le parent) ayant défini ces
champs.

je dirais plutôt si les champs protégés impliqués appartiennent à
l'instance courante, en propre par sa classe ou hérité d'une de ses
super-classes.

void Pixel::foo(){
x = 2 * x;
y = 3 * y;
};

est valide

void Pixel::bar(){
Point pt(*this);
x = 2 * pt.x;
y = 3 * pt.y;
}

est invalide 'pt' n'est pas 'this'; dans le scope de 'bar' c'est une
variable bien distincte avec ses règles propres, le fait que 'this' et
'pt' partagent un parent commun ne doit pas de droit particulier.

Sylvain.
Back to top
James Kanze
Guest





PostPosted: Sun Apr 01, 2007 3:07 pm    Post subject: Re: Problème d'héritage Reply with quote

On Mar 31, 11:30 pm, Sylvain <noS...@mail.net> wrote:
Quote:
James Kanze wrote on 29/03/2007 09:12:

2) Le compilateur me jette, il ne veut pas de p.x ou p.y,
pourtant les attributs x et y sont protected ???

C'est la règle. Protected permet l'accès dans une classe dérivée
aux éléments de la classe de base seulement /si l'objet est de
la même classe (ou d'une classe dérivée) que celle qui fait
l'accès./

la classe (d'objet) qui manipule les champs hérités est nécessairement
de la "même classe ou dérivée" que celle (le parent) ayant défini ces
champs.

Je me suis probablement mal exprimé. (À vrai dire, je ne trouve
pas une façon claire à expliquer la chose.) Si tu as une classe
Base, qui définit des éléments protégés, une classe qui en
dérive, Derived, ne peut accéder aux éléments protégés que dans
les Base des Derived, et non dans les Base tout court, ni des
Base d'autres classes dérivées.

Quote:
je dirais plutôt si les champs protégés impliqués appartiennent à
l'instance courante, en propre par sa classe ou hérité d'une de ses
super-classes.

void Pixel::foo(){
x = 2 * x;
y = 3 * y;

};

est valide

void Pixel::bar(){
Point pt(*this);
x = 2 * pt.x;
y = 3 * pt.y;
}

est invalide 'pt' n'est pas 'this'; dans le scope de 'bar' c'est une
variable bien distincte avec ses règles propres, le fait que 'this' et
'pt' partagent un parent commun ne doit pas de droit particulier.

Non. La protection en C++ ne se base jamais sur l'instance, mais
toujours sur le type. Considérons :

class Base
{
protected:
int x ;
} ;

class Derived : public Base
{
public:
void f() ;
} ;

class OtherDerived : public Base
{
} ;

void
Derived::f()
{
Base b ;
Derived d1 ;
OtherDerived d2 ;
int i ;

i = this->x ; // (ou simlement x) légal
i = b.x ; // illégal
i = d1.x ; // légal
i = d2.x ; // illégal
}

La règle, c'est que la classe Derived peut accéder aux membres
de la classe Base si et seulement si le type static de
l'expression d'accès a un type Derived (ou un type dérivé de
Derived).

Il y avait des bonnes raisons pour ceci. Mais je ne me les
rappelle plus, et vue la confusion qu'il cause, je me démande si
c'était vraiment une bonne idée, quelque soit la validité des
raisons.

--
James Kanze (Gabi Software) email: james.kanze (AT) gmail (DOT) com
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
Back to top
Sylvain
Guest





PostPosted: Sun Apr 01, 2007 4:24 pm    Post subject: Re: Problème d'héritage Reply with quote

James Kanze wrote on 01/04/2007 12:07:
Quote:

Je me suis probablement mal exprimé. [...]

un partout ;)

Quote:
je dirais plutôt si les champs protégés impliqués appartiennent à
l'instance courante, [...]

Non. La protection en C++ ne se base jamais sur l'instance, mais
toujours sur le type.

oui, merci de cette rectification.

Quote:
La règle, c'est que la classe Derived peut accéder aux membres
de la classe Base si et seulement si le type static de
l'expression d'accès a un type Derived (ou un type dérivé de
Derived).

c'est plus clair comme cela.

Sylvain.
Back to top
Fabien Chêne
Guest





PostPosted: Fri Apr 06, 2007 12:09 am    Post subject: Re: Problème d'héritage Reply with quote

"James Kanze" <james.kanze (AT) gmail (DOT) com> writes:

Quote:
class Base
{
protected:
int x ;
} ;

class Derived : public Base
{
public:
void f() ;
} ;

class OtherDerived : public Base
{
} ;

void
Derived::f()
{
Base b ;
Derived d1 ;
OtherDerived d2 ;
int i ;

i = this->x ; // (ou simlement x) légal
i = b.x ; // illégal
i = d1.x ; // légal
i = d2.x ; // illégal
}

La règle, c'est que la classe Derived peut accéder aux membres
de la classe Base si et seulement si le type static de
l'expression d'accès a un type Derived (ou un type dérivé de
Derived).

Il y avait des bonnes raisons pour ceci. Mais je ne me les
rappelle plus, et vue la confusion qu'il cause, je me demande si
c'était vraiment une bonne idée, quelque soit la validité des
raisons.

Je ne sais pas exactement à quoi tu penses, mais il est commode que le
code suivant fonctionne :

struct D
{
D( D const& d )
: x( d.x )
{}
private:
int x;
};

Et que le compilateur puisse aisément générer le constructeur de copie
lorsque celui-ci n'est pas déclaré.

J'ai l'impression - mais non la preuve - que l'accès aux membres de
'Base' depuis une expression de type statique 'Derived' est nécessaire
si l'on a voulu faire en sorte que le code précédent fonctionne, et
que le langage reste cohérent.

L'idée est la même pour l'accès à 'Base' depuis un type dérivé de
'Derived'.

--
Fab
Back to top
James Kanze
Guest





PostPosted: Fri Apr 06, 2007 9:11 am    Post subject: Re: Problème d'héritage Reply with quote

On Apr 5, 9:09 pm, fabien.ch...@gmail.com (Fabien Chêne) wrote:
Quote:
"James Kanze" <james.ka...@gmail.com> writes:
class Base
{
protected:
int x ;
} ;

class Derived : public Base
{
public:
void f() ;
} ;

class OtherDerived : public Base
{
} ;

void
Derived::f()
{
Base b ;
Derived d1 ;
OtherDerived d2 ;
int i ;

i = this->x ; // (ou simlement x) légal
i = b.x ; // illégal
i = d1.x ; // légal
i = d2.x ; // illégal
}

La règle, c'est que la classe Derived peut accéder aux membres
de la classe Base si et seulement si le type static de
l'expression d'accès a un type Derived (ou un type dérivé de
Derived).

Il y avait des bonnes raisons pour ceci. Mais je ne me les
rappelle plus, et vue la confusion qu'il cause, je me demande si
c'était vraiment une bonne idée, quelque soit la validité des
raisons.

Je ne sais pas exactement à quoi tu penses, mais il est commode que le
code suivant fonctionne :

struct D
{
D( D const& d )
: x( d.x )
{}
private:
int x;
};

Et il fonctionne. Je ne sais pas exactement à quoi tu penses,
mais le contrôle d'accès en C++ est toujours par classe, et
jamais par objet. Parfois, on préfèrerait par objet, mais comme
tu dis, ça rendra quelques idiomes essentiels extrèmement
compliqués.

La seule chose en question, c'était le comportement du contrôle
d'accès des membres protégés depuis une classe dérivée. Une
classe dérivée (Derived) n'a droit d'accès à des membres
protégés de la base (Base) que dans les Base des Derived, et non
dans n'importe quelle Base.

--
James Kanze (Gabi Software) email: james.kanze (AT) gmail (DOT) com
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
Back to top
Fabien Chêne
Guest





PostPosted: Fri Apr 06, 2007 5:32 pm    Post subject: Re: Problème d'héritage Reply with quote

"James Kanze" <james.kanze (AT) gmail (DOT) com> writes:

[...]
Quote:
La règle, c'est que la classe Derived peut accéder aux membres
de la classe Base si et seulement si le type static de
l'expression d'accès a un type Derived (ou un type dérivé de
Derived).

Il y avait des bonnes raisons pour ceci. Mais je ne me les
rappelle plus, et vue la confusion qu'il cause, je me demande si
c'était vraiment une bonne idée, quelque soit la validité des
raisons.

Je ne sais pas exactement à quoi tu penses, mais il est commode que le
code suivant fonctionne :

struct D
{
D( D const& d )
: x( d.x )
{}
private:
int x;
};

Et il fonctionne. Je ne sais pas exactement à quoi tu penses,
mais le contrôle d'accès en C++ est toujours par classe, et
jamais par objet.

Oui, et je trouve logique les règles d'accès qui en découlent - accès
aux membres des bases, etc.

Quote:
Parfois, on préfèrerait par objet, mais comme tu dis, ça rendra
quelques idiomes essentiels extrèmement compliqués.

Dans quel contexte pourrais t'on préférer un contrôle d'accès par
objet ? J'avoue que je ne vois pas.

Je confesse que lorsque j'ai écrit mon premier constructeur de copie,
j'ai cherché à écrire ceci (ie je m'attendais à un contrôle par
objet) :

D( D const& d )
: x( d.get_x() )
{}

avec get_x() fonction membre public de D.

Mais on se rend bien compte que si cela fonctionnait ainsi, ce ne
serait pas viable ; pour permettre au compilateur de générer un
constructeur de copie, il aurait qu'il donne au constructeur de copie
un acces "exceptionel" aux membres privés et protégés, ou supprimer la
génération du constructeur de copie s'il y a un membre privé ou
protégé, ou ... bref.

--
Fab
Back to top
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ (French) All times are GMT
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.