Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Problème d'héritage

15 réponses
Avatar
Philip K. Dick
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::x' is protected
pixel.cc:27: within this context

Une idée ?

PKD

5 réponses

1 2
Avatar
Sylvain
James Kanze wrote on 01/04/2007 12:07:

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


un partout ;)

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.

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.


Avatar
fabien.chene
"James Kanze" 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 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

Avatar
James Kanze
On Apr 5, 9:09 pm, (Fabien Chêne) wrote:
"James Kanze" 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:
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
fabien.chene
"James Kanze" writes:

[...]
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.

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



Avatar
James Kanze
On Apr 6, 2:32 pm, (Fabien Chêne) wrote:
"James Kanze" writes:

[...]
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.


Quand on a à faire à des objets entité, où chaque objet est
responsable de lui-même, et non des autres objets (qu'ils soient
du même type ou non). Le fait que le contrôle d'accès se fait au
niveau de la classe, et non de l'objet, ne trouve réelement sa
raison d'être que quand les objets sont des valeurs.

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.


Oui, mais il y a beaucoup de types qui ne supportent pas la
copie. Dans beaucoup d'application, même, c'est le cas de la
majorité des types.

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


1 2