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

classe abstraite / "java implement" / ...

14 réponses
Avatar
meow
Bonjour, d=E9sol=E9 pour le titre un peu vague mais je ne vois pas
comment d=E9crire mon probl=E8me en une phrase... Le plus simple c'est de
regarder le petit exemple ci dessous :

/*! A abstraite et donc non instenciable */
class A{ public:
la_fonction_que_je_dois_implementer_pour_etre_un_A()=3D0;
}

/*! AA instenciable */
class AA:public A{ public:
la_fonction_que_je_dois_implementer_pour_etre_un_A(){;};
}

/*! aggr=E8ge un A et donc ne compile pas */
B{
A _a;
B(A& a):_a(a){;}
}

Donc voil=E0 l'id=E9e : je cherche =E0 d=E9crire que B va aggreger un objet
qui contient une fonction
la_fonction_que_je_dois_implementer_pour_etre_un_A, sachant que
l'impl=E9mentation de cette fonction d=E9pendra de l'objet qu'on passera
au constructeur. A terme j'aurai AA:public A, mais aussi AB:public A,
etc... et je veux pouvoir aggr=E9ger indiff=E9rement un AA ou un AB dans
B=2E..
A priori si je retires le "=3D0" dans A =E7a se passe bien, mais =E0 ce
moment l=E0 je n'ai aucun moyen d'empecher l'utilisateur de me fournir
dirrectement un A, auqel cas la_fonction_... ne sera pas
impl=E9ment=E9e...

10 réponses

1 2
Avatar
Pierre Barbier de Reuille
Bonjour, désolé pour le titre un peu vague mais je ne vois pas
comment décrire mon problème en une phrase... Le plus simple c'est de
regarder le petit exemple ci dessous :

/*! A abstraite et donc non instenciable */
class A{ public:
la_fonction_que_je_dois_implementer_pour_etre_un_A()=0;
}

/*! AA instenciable */
class AA:public A{ public:
la_fonction_que_je_dois_implementer_pour_etre_un_A(){;};
}

/*! aggrège un A et donc ne compile pas */
B{
A _a;
B(A& a):_a(a){;}
}

Donc voilà l'idée : je cherche à décrire que B va aggreger un objet
qui contient une fonction
la_fonction_que_je_dois_implementer_pour_etre_un_A, sachant que
l'implémentation de cette fonction dépendra de l'objet qu'on passera
au constructeur. A terme j'aurai AA:public A, mais aussi AB:public A,
etc... et je veux pouvoir aggréger indifférement un AA ou un AB dans
B...
A priori si je retires le "=0" dans A ça se passe bien, mais à ce
moment là je n'ai aucun moyen d'empecher l'utilisateur de me fournir
dirrectement un A, auqel cas la_fonction_... ne sera pas
implémentée...



Il faut garder à l'esprit que, en C++, le polymorphisme passe
nécessairement par l'utilisation de pointeurs ou de références.

Donc, si l'objet dérivant de A est décidé à la création et ne peut pas
changer tu peux écrire :

class B
{
A& _a;
B(A& a) : _a(a) {}
};

Sinon il faut mettre un pointeur :

class B
{
A* _a;
B(A* a) : _a(a) {}
};

mais avec un pointeur, le mieux est encore d'utiliser un "pointeur
intelligent" ... genre le shared_ptr du projet Boost : http://www.boost.org

Pierre

Avatar
kanze
meow wrote:
Bonjour, désolé pour le titre un peu vague mais je ne vois pas
comment décrire mon problème en une phrase... Le plus simple
c'est de regarder le petit exemple ci dessous :

/*! A abstraite et donc non instenciable */
class A{ public:
la_fonction_que_je_dois_implementer_pour_etre_un_A()=0;
}

/*! AA instenciable */
class AA:public A{ public:
la_fonction_que_je_dois_implementer_pour_etre_un_A(){;};
}

/*! aggrège un A et donc ne compile pas */
B{
A _a;
B(A& a):_a(a){;}
}

Donc voilà l'idée : je cherche à décrire que B va aggreger un
objet qui contient une fonction
la_fonction_que_je_dois_implementer_pour_etre_un_A, sachant
que l'implémentation de cette fonction dépendra de l'objet
qu'on passera au constructeur.


Mais ce n'est pas ce que tu as écrit. Tu as écrit que tu veux
une copie d'un A, qui est en A -- si on te donne une dérivée de
A, c'est bien, mais tu ne va copier que la partie A de cette
dérivée.

Tu as cité Java dans le sujet, alors... Si tu fais comme en
Java, et utilises un pointeur ou une référence, ça marche.

A terme j'aurai AA:public A, mais aussi AB:public A, etc... et
je veux pouvoir aggréger indifférement un AA ou un AB dans
B...

A priori si je retires le "=0" dans A ça se passe bien, mais à
ce moment là je n'ai aucun moyen d'empecher l'utilisateur de
me fournir dirrectement un A, auqel cas la_fonction_... ne
sera pas implémentée...


Pire. Quoique te fournisse l'utilisateur, tu ne vas en copier
que la partie A.

D'une certaine côté, Java et C++ sont pareil ici. Un objet a un
type donné, toujours. Ce type est determiné lors de la
construction, et ne change jamais. À l'encontre de Java, en
revanche, en C++ les variables peuvent être des objets -- en
fait, elles le sont toujours, parce qu'en C++, un pointeur est
aussi un objet. Et le type d'une variable, c'est bien le type de
sa declaration. Tandis qu'en Java, les variables sont des
références, et ne sont pas des objets. C'est un autre point de
vue -- le Java est ici plus compliqué que le C++, parce qu'il
melange des paradigmes.

--
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
Fabien LE LEZ
On 8 Dec 2005 23:54:04 -0800, "kanze" :

en C++ les variables peuvent être des objets -- en
fait, elles le sont toujours, parce qu'en C++, un pointeur est
aussi un objet.


Tu oublies les références, qui sont des variables avec un statut plus
ou moins bâtard.

Avatar
meow
@pierre
Merci, en effet, ça fonctionne.
Franchement, je commence à me décourrager devant la somme de
connaissances à aquerrir avant de pouvoir coder un peu proprement en
C++... :(

La solution avec le pointeur me plait moins parce que B(A *a) sous
entend que l'objet A que je vais abriter dans B existe à l'extérieur
et y est donc modifiable. Le mieux serait que j'en fasse une copie...
genre :

class B{
A *_a;
B(A& a){_a=new A(a);};

non ?

@kanze
Mais ce n'est pas ce que tu as écrit. Tu as écrit que tu veux
une copie d'un A, qui est en A -- si on te donne une dérivée de
A, c'est bien, mais tu ne va copier que la partie A de cette
dérivée.
Hum... Dans mon cas ce ne sera pas forcément problématique.

Néanmoins, c'est un problème que je n'avais pas vu. Que faire ?

Tu as cité Java dans le sujet, alors... Si tu fais comme en
Java, et utilises un pointeur ou une référence, ça marche.
Je ne connais pas Java, je ne l'ai cité ici que parce que ceux qui

m'entourrent ici programment en java et qu'ils m'ont parlé des
interfaces... Un mécanisme qui semble se rapprocher de ce que je veux
faire.

Maintenant je ne vois pas bien en quoi l'utilisation du pointeur
résoud le problème précédent... Je veux dire, si _a pointe vers
l'extérieur de B comme l'a suggéré Pierre, OK, l'objet pointé par
_a peut etre d'une classe fille (encore faudra t'il assaisonner a la
sauce virtual, non ?), mais il n'est pas "abrité" par B. Et si je fais
mon micmac _a=new A(a), j'obtiens bien un pointeur sur A et je fiche à
la poubelle les spécificités des filles.

Encore une fois, dans mon cas ça ne semble pas etre un probleme dans
la mesure où tout ce qui m'intéresse c'est la fonction déclarée
dans A et à définir dans les filles. Une petite question tout de meme
dans le cas où dans AA cette fonction en appellerait une autre elle
aussi dans AA:

class AA:public A{
protected:
fonction_specifique_a_AA();
public:

la_fonction_que_je_dois_implementer_pour_etre_un_A(){fonction_specifique_a_ AA();};
}

fonction_spécifique_a_AA() ne sera pas définie dans mon objet B::a.
Cela étant ça ne devrait pas poser de probleme dans la mesure où
tout se compile bien et statiquement... Mais si maintenant
fonction_specifique_a_AA(); était virtuelle... vu que la résolution
est dynamique ça risque pas d'aller dans le mur ?

Avatar
Pierre Barbier de Reuille
meow wrote:
@pierre
Merci, en effet, ça fonctionne.
Franchement, je commence à me décourrager devant la somme de
connaissances à aquerrir avant de pouvoir coder un peu proprement en
C++... :(

La solution avec le pointeur me plait moins parce que B(A *a) sous
entend que l'objet A que je vais abriter dans B existe à l'extérieur
et y est donc modifiable. Le mieux serait que j'en fasse une copie...
genre :

class B{
A *_a;
B(A& a){_a=new A(a);};

non ?


Oula, non malheureux ;)

Si tu veux faire une copie, la solution consiste à ajouter dans ta
classe A une méthode virtuelle de recopie :

class A
{
public:
...
virtual A* copy() const = 0;
};

que tu implémentes très simplement dans une sous-classe AA :

class AA : public A
{
public:
...
virtual A* copy() const { return new AA(*this); }
};

du coup ton constructeur dans B devient :

class B
{
B(const A& a)
: _a(a.copy())
{ }
A *_a;
};



@kanze

Mais ce n'est pas ce que tu as écrit. Tu as écrit que tu veux
une copie d'un A, qui est en A -- si on te donne une dérivée de
A, c'est bien, mais tu ne va copier que la partie A de cette
dérivée.


Hum... Dans mon cas ce ne sera pas forcément problématique.
Néanmoins, c'est un problème que je n'avais pas vu. Que faire ?


Tu as cité Java dans le sujet, alors... Si tu fais comme en
Java, et utilises un pointeur ou une référence, ça marche.


Je ne connais pas Java, je ne l'ai cité ici que parce que ceux qui
m'entourrent ici programment en java et qu'ils m'ont parlé des
interfaces... Un mécanisme qui semble se rapprocher de ce que je veux
faire.

Maintenant je ne vois pas bien en quoi l'utilisation du pointeur
résoud le problème précédent... Je veux dire, si _a pointe vers
l'extérieur de B comme l'a suggéré Pierre, OK, l'objet pointé par
_a peut etre d'une classe fille (encore faudra t'il assaisonner a la
sauce virtual, non ?), mais il n'est pas "abrité" par B. Et si je fais
mon micmac _a=new A(a), j'obtiens bien un pointeur sur A et je fiche à
la poubelle les spécificités des filles.

Encore une fois, dans mon cas ça ne semble pas etre un probleme dans
la mesure où tout ce qui m'intéresse c'est la fonction déclarée
dans A et à définir dans les filles. Une petite question tout de meme
dans le cas où dans AA cette fonction en appellerait une autre elle
aussi dans AA:

class AA:public A{
protected:
fonction_specifique_a_AA();
public:

la_fonction_que_je_dois_implementer_pour_etre_un_A(){fonction_specifique_a_AA();};
}

fonction_spécifique_a_AA() ne sera pas définie dans mon objet B::a.
Cela étant ça ne devrait pas poser de probleme dans la mesure où
tout se compile bien et statiquement... Mais si maintenant
fonction_specifique_a_AA(); était virtuelle... vu que la résolution
est dynamique ça risque pas d'aller dans le mur ?




Avatar
meow
Oh... Bein au passage tu as répondu à une des questions que je posais
à Kanze... :D
Merci beaucoup. Et oui, je comprends le principe... C'est tout de meme
bien un peu frustrant de pas trouver ces méthodes tout seul :(
Rassurez moi, vous pratiquez le C++ depuis longtemps, non ?
Avatar
Fabien LE LEZ
On 9 Dec 2005 07:17:59 -0800, "meow" :

Rassurez moi, vous pratiquez le C++ depuis longtemps, non ?


Pour James (Kanze), c'est sûr -- je crois bien qu'il l'a vu naître ;-)

À part ça, rassure-toi, en moins de 5 ans on arrive à acquerir tous
ces réflexes salutaires.

Avatar
meow
À part ça, rassure-toi, en moins de 5 ans on arrive à acquerir tous
ces réflexes salutaires.
'''O_o C'est vraiment sensé me rassurer ? 5 ans ?


Avatar
Jean-Marc Bourguet
"meow" writes:

À part ça, rassure-toi, en moins de 5 ans on arrive à acquerir tous
ces réflexes salutaires.
'''O_o C'est vraiment sensé me rassurer ? 5 ans ?



Apres 5 ans, on a acquis le reflexe salutaire de se considerer comme
ignorant :-)

A+

--
Jean-Marc
FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ
C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index.html
Site de usenet-fr: http://www.usenet-fr.news.eu.org


Avatar
Pierre Barbier de Reuille
Jean-Marc Bourguet wrote:
"meow" writes:


À part ça, rassure-toi, en moins de 5 ans on arrive à acquerir tous
ces réflexes salutaires.


'''O_o C'est vraiment sensé me rassurer ? 5 ans ?



Apres 5 ans, on a acquis le reflexe salutaire de se considerer comme
ignorant :-)

A+



De toute façon, je ne connais pas de langages dans lequel on peut être
efficace en moins de 3 ans ! Même les langages à apprentissage dit
"rapide" (genre Python) demandent beaucoup de temps avant d'arriver à
voir, à l'avance, ce qui marchera bien pour de gros projets.



1 2