utilisation de classe friend

utilisation de classe friend - C++ - Programmation

Marsh Posté le 03-10-2005 à 20:54:53    

Salut,
 
Je me retrouve dans un cas ou j'utilise une classe amie. Comme j'ai souvent lu que ca pouvait cacher une mauvaise conception, je demande à tout hasard si c'est le cas :
- la classe Foo utilise la classe A.
- la classe Foo est passé en paramètre de la classe Bar
- la classe Bar doit utiliser la classe A
 
Bon le plus simple serait effectivement de faire un get dans la classe Foo mais je veux cacher l'existence de A. D'où l'utilisation du friend.
 
Qu'en pensez-vous ?
 
Merci.
 

Reply

Marsh Posté le 03-10-2005 à 20:54:53   

Reply

Marsh Posté le 04-10-2005 à 01:22:33    

je vois pas pourquoi tu mettrais un friend.

Reply

Marsh Posté le 04-10-2005 à 10:58:53    

Code :
  1. class A
  2. {
  3. public:
  4.      igla();
  5.      igleu();
  6. };
  7. class Foo : public A
  8. {
  9. public:
  10.    igleu();
  11. };
  12. class Bar
  13. {
  14. public:
  15.    void DoIt( Foo & );
  16. };
  17. void Bar::DoIt( Foo &TheFoo )
  18. {
  19.   TheFoo.igleu();  // Foo::igleu()
  20.   TheFoo.igla();  // A::igla();
  21.   TheFoo.A::igleu();    // A::igleu();
  22. }

Message cité 2 fois
Message édité par bjone le 04-10-2005 à 17:36:35
Reply

Marsh Posté le 04-10-2005 à 12:22:48    

alors déjà il manque un virtuel
 
TheFoo.A::igleu();    // A::igleu();
 
ça jamais jamais jamais jamais ! Il ne faut pas appeler depuis l'extérieur
 
Dérivé::Base::Fonction() car tu violes le mécanisme virtuel en passant outre Dérivé::Fonction(). C'est catastrophique.

Reply

Marsh Posté le 04-10-2005 à 12:27:49    

bjone a écrit :

Code :
  1. class A
  2. {
  3. public:
  4.      igla();
  5.      igleu();
  6. };
  7. class Foo : public A
  8. {
  9. public:
  10.    igleu();
  11. };



t'as pas déclaré igleu() en virtual :o
 
edit: [:benou_grilled]


Message édité par Harkonnen le 04-10-2005 à 12:28:10
Reply

Marsh Posté le 04-10-2005 à 17:26:32    

Taz a écrit :

alors déjà il manque un virtuel
 
TheFoo.A::igleu();    // A::igleu();
 
ça jamais jamais jamais jamais ! Il ne faut pas appeler depuis l'extérieur
 
Dérivé::Base::Fonction() car tu violes le mécanisme virtuel en passant outre Dérivé::Fonction(). C'est catastrophique.


 
heu pour moi, le virtual est nécessaire quand tu manipules tes instances via un pointeur sur A (sur la classe de base).
là je passe par un Foo & (ou Foo, ou const Foo &, s'en fous).
je vois pas en quoi j'ai besoin d'un virtual sur igleu(), si je veux utiliser l'igleu de la classe de base et non celui de la dérivée.
 
et passer outre Dérivé::Fonction(), pour utiliser Base::Fonction(), c'est ce que je veux faire, t'as un lien ou une page du strup qui dit que ce que je veux faire c'est mal ?

Message cité 1 fois
Message édité par bjone le 04-10-2005 à 17:31:57
Reply

Marsh Posté le 04-10-2005 à 17:29:11    

ou alors on est pas dans le même contexte ?
 
là je suis pas dans le cas où je manipules des instances de classes dérivées via un pointeur sur une classe de base (ok pour le virtual par design dans ce cas), mais je suis dans le cas où je manipule une instance de classe dérivée via elle-même, et je veux appeller une méthode de la classe de base.
 
(tiens d'ailleurs je me suis planté pour igla)


Message édité par bjone le 04-10-2005 à 17:36:53
Reply

Marsh Posté le 04-10-2005 à 19:06:45    

perdu. La virtualité fonctionne avec les pointeurs et les références. Passé par copie un Foo là où on attend un A, c'est mettre une grosse boîte dans une petite : tu perds de l'information, tu casses ton système objet.

Reply

Marsh Posté le 04-10-2005 à 19:10:10    

bjone a écrit :


et passer outre Dérivé::Fonction(), pour utiliser Base::Fonction(), c'est ce que je veux faire, t'as un lien ou une page du strup qui dit que ce que je veux faire c'est mal ?


c'est pas la même chose du tout ça.
 
 
Mais de puis l'extérieur faire un
 
Objet::BasePublique::fonction_membre();
 
c'est comme faire un
 
*((int*)&objet + 3) = 42;

Reply

Marsh Posté le 04-10-2005 à 20:37:33    

bjone a écrit :

Code :
  1. class A
  2. {
  3. public:
  4.      igla();
  5.      igleu();
  6. };
  7. class Foo : public A
  8. {
  9. public:
  10.    igleu();
  11. };
  12. class Bar
  13. {
  14. public:
  15.    void DoIt( Foo & );
  16. };
  17. void Bar::DoIt( Foo &TheFoo )
  18. {
  19.   TheFoo.igleu();  // Foo::igleu()
  20.   TheFoo.igla();  // A::igla();
  21.   TheFoo.A::igleu();    // A::igleu();
  22. }



 
C'est l'exemple classique du masquage de nom.
Foo::igleu masque A::igleu (pas considéré par le lookup car le nom igleu est trouvé dans la scope de la class Foo)
pour y acceder, c'est comme tu as fait TheFoo.A::igleu()
Mais c'est moche, il vaut mieux faire participer A::igleu à la résolution de surcharge avec using A::igleu;
 
(le tout sans virtualité).
 
 

Reply

Marsh Posté le 04-10-2005 à 20:37:33   

Reply

Marsh Posté le 04-10-2005 à 20:47:15    

Ok en dérivant la classe A, j'y avait pensé aussi seulement je sais pas si je peux le faire : en fait j'écrit un wrapper pour ADO, je vais voir ca.
 
Et merci pour vos réponses  :jap:

Reply

Marsh Posté le 04-10-2005 à 20:47:59    

y a pas de masquage de nom, c'est juste une putain de bidouille pour tout foutre en l'air.

Reply

Marsh Posté le 04-10-2005 à 20:53:58    

un peu qu'y a masquage de nom !
le code que l'ai cité ne fout rien en l'air en tout cas.

Reply

Marsh Posté le 04-10-2005 à 21:11:35    

Code :
  1. class Foo
  2. {
  3.   public:
  4.   virtual void do_something();
  5. };
  6. class LockedFoo : public Foo
  7. {
  8.   public:
  9.   virtual void do_something()
  10.   { Lock l; Foo::do_something(); }
  11. };
  12. void bar(Foo &f)
  13. {
  14.    f.Foo::do_something();
  15. }


 
boom. Perdu.
 
edit: c'est n'importe quoi. Pourquoi laisser quelqu'un redéfinir un service pour ensuite le foutre en l'air et pisser sur ses contraintes et invariants ?


Message édité par Taz le 04-10-2005 à 21:12:58
Reply

Marsh Posté le 04-10-2005 à 21:28:15    

j'ai précisé "sans virtualité" :)
 
pour ton edit :
Quelle idée de mettre une fonction virtuelle publique aussi ...

Reply

Marsh Posté le 04-10-2005 à 22:48:20    

sans virtualité c'est un non-sens objet
 
edit: sinon autant donner des noms différents.

Message cité 1 fois
Message édité par Taz le 04-10-2005 à 22:59:28
Reply

Marsh Posté le 04-10-2005 à 22:59:15    

mais pas un non sens en c++.
 
Et meme en virtuel, si tu renvoie dans ses 22 ta fonction virtuelle *publique*, tu peux empecher l'utilisateur d'appeler la fonction de la classe de base.

Reply

Marsh Posté le 04-10-2005 à 23:02:27    

rien compris. C'est pas parce que le C++ te permet de tout faire que tu peux le faire. Pour moi tout ça c'est proche de l'UB.

Reply

Marsh Posté le 04-10-2005 à 23:19:37    

Code :
  1. #include <iostream>
  2. struct Lock {};
  3. class Foo
  4. {
  5. public:
  6.     void do_something() const
  7. { do_something_core(); }
  8.     virtual ~Foo() {}
  9. protected:
  10.     virtual void do_something_core() const
  11. { std::cout << "Foo::do_something_core()\n"; }
  12. };
  13.  
  14. class LockedFoo : public Foo
  15. {
  16. private:
  17.     virtual void do_something_core() const
  18. { Lock l; Foo::do_something(); std::cout << "LockedFoo::do_something()\n"; }
  19. };
  20.  
  21. void bar(Foo &f)
  22. {
  23.     f.Foo::do_something(); // essaye d'appeler la mauvaise ...
  24. }
  25. int main()
  26. {
  27.     Foo foo;
  28.     bar(foo);
  29. }

Message cité 1 fois
Message édité par ++fab le 05-10-2005 à 00:13:54
Reply

Marsh Posté le 04-10-2005 à 23:35:41    

joli pléonasme.

Reply

Marsh Posté le 04-10-2005 à 23:40:08    

Taz a écrit :

edit: sinon autant donner des noms différents.


 
pas forcément (je suis d'humeur taquine) :
 

Code :
  1. class B
  2. {
  3. protected:
  4.     ~B() {}
  5. public:
  6.     void foo( double ) const {}
  7. };
  8. struct D : public B
  9. {
  10.     using B::foo;
  11. private:
  12.     void foo( int ) const; // int interdit
  13. };
  14. int main()
  15. {
  16.     D d;
  17.     d.foo(4);
  18. }


Message édité par ++fab le 05-10-2005 à 00:10:23
Reply

Marsh Posté le 04-10-2005 à 23:56:44    

Taz a écrit :

joli pléonasme.


effectivement !
j'ai édité.
réédité.


Message édité par ++fab le 05-10-2005 à 00:14:18
Reply

Marsh Posté le 05-10-2005 à 00:02:27    

Taz a écrit :

perdu. La virtualité fonctionne avec les pointeurs et les références. Passé par copie un Foo là où on attend un A, c'est mettre une grosse boîte dans une petite : tu perds de l'information, tu casses ton système objet.


 
ok pour l'aspect Foo passé via un A par copie qui peut corrompre la cohérence de l'objet (suivant interdépendances entre la base et la classe dérivé, et surtout si il y a des virtuals qui vont employer des ressources perdues).
-mais- où je passe par copie un Foo là ou on attends un A dans le code que j'ai donné ?
 
 
dans le code que j'ai mis SANS virtual ( pourquoi mettre du virtual partout ? c'est pas une obligation quand tu sais ce que tu fais, tout est question de savoir a travers quelle "définition" de classe tu manipules l'objet, si tu manipules des objets dérivés via une classe de base, oui il faut du virtual pour la résolution au runtime, mais si tu manipules directement a travers une classe dérivée, tu connais explicitement quelle méthode utiliser au compile time), je vois pas ce qui serait illégal.
 
de plus, la question du monsieur c'est:
 
- la classe Foo utilise la classe A.
- la classe Foo est passé en paramètre de la classe Bar
- la classe Bar doit utiliser la classe A  
 
désolé j'ai essayé de lui proposer une solution qui me semble légale, et je vois pas pourquoi il serait obligatoire de coller du virtual si jamais tu sais a l'avance que tu vas manipuler par la classe dérivée...
de plus le cas avec igleu() dans la dérivée et la base est pour montrer comment on peut effectivement revenir au scope de la classe de base.


Message édité par bjone le 05-10-2005 à 00:04:23
Reply

Marsh Posté le 05-10-2005 à 07:08:56    

++fab a écrit :

Code :
  1. #include <iostream>
  2. struct Lock {};
  3. class Foo
  4. {
  5. public:
  6.     void do_something() const
  7. { do_something_core(); }
  8.     virtual ~Foo() {}
  9. protected:
  10.     virtual void do_something_core() const
  11. { std::cout << "Foo::do_something_core()\n"; }
  12. };
  13.  
  14. class LockedFoo : public Foo
  15. {
  16. private:
  17.     virtual void do_something_core() const
  18. { Lock l; Foo::do_something_core(); std::cout << "LockedFoo::do_something_core()\n"; }
  19. };
  20.  
  21. void bar(Foo &f)
  22. {
  23.     f.Foo::do_something(); // essaye d'appeler la mauvaise ...
  24. }
  25. int main()
  26. {
  27.     Foo foo;
  28.     bar(foo);
  29.     LockedFoo foo2;
  30.     bar(foo2);
  31. }



 
décidément !


Message édité par ++fab le 05-10-2005 à 07:11:03
Reply

Marsh Posté le 05-10-2005 à 11:55:32    

tu prends pas beaucoup de risque là ...

Reply

Marsh Posté le 05-10-2005 à 13:44:00    

Code :
  1. void bar(Foo &f)
  2. {
  3.     f.Foo::do_something(); // essaye d'appeler la mauvaise ...  
  4. }


transforme le passage par référence en passage par copie, et voilà.
 
J'ai pas bien compris le problème, notamment au niveau de "la classe Bar doit utiliser la classe A" alors qu'elle reçoit un Foo, et surtout que tu "veux cacher l'existence de A".
Si c'est juste au niveau de l'interface d'utilisation qui doit être commune entre A et Foo, mais que Foo doit en interne utiliser A sans que ce soit visible, l'héritage privé me semble une bonne solution.
Si Foo n'est pas un A ("la classe Foo utilise la classe A" ), l'héritage plublic ne me semble pas indiqué.
A moins que ce ne soit à A de dériver de Foo, et non l'inverse.


---------------
FAQ fclc++ - FAQ C++ - C++ FAQ Lite
Reply

Marsh Posté le 05-10-2005 à 19:07:52    

HelloWorld a écrit :

Code :
  1. void bar(Foo &f)
  2. {
  3.     f.Foo::do_something(); //  ( ou  f.do_something() quoi )
  4. }


transforme le passage par référence en passage par copie, et voilà.


 
au contraire. Le comportement polymorphique va disparaitre.
 
 

Citation :

J'ai pas bien compris le problème, notamment au niveau de "la classe Bar doit utiliser la classe A" alors qu'elle reçoit un Foo, et surtout que tu "veux cacher l'existence de A".
Si c'est juste au niveau de l'interface d'utilisation qui doit être commune entre A et Foo, mais que Foo doit en interne utiliser A sans que ce soit visible, l'héritage privé me semble une bonne solution.
Si Foo n'est pas un A ("la classe Foo utilise la classe A" ), l'héritage plublic ne me semble pas indiqué.
A moins que ce ne soit à A de dériver de Foo, et non l'inverse.


 
ou alors, si c'est faisable, ne pas hériter et diminuer ainsi le couplage. Utiliser des données membres plutot que des héritages privés. Mais la description de son problème est trop flou pour pouvoir lui dire précisément fais ci, fais ça, AMHA.

Reply

Marsh Posté le 05-10-2005 à 19:13:20    

Taz a écrit :

tu prends pas beaucoup de risque là ...


 
Oui, il n'y a qu'une seule fonction membre publique non virtuelle. Et le polymorphisme marche en dessous.
Comme ça, il n'est pas possible d'appeler la mauvaise fonction virtuelle. Ca représente quand meme un certain confort par rapport à la solution médiocrissime des fonctions virtuelles publiques.

Reply

Marsh Posté le 05-10-2005 à 19:20:12    

mais bien sur ..

Reply

Marsh Posté le 05-10-2005 à 19:23:13    

Taz a écrit :

mais bien sur ..


 
... que t'es aux fraises sur ce coup.

Reply

Marsh Posté le 06-10-2005 à 10:14:13    

++fab a écrit :


HelloWorld a écrit :

Code :
  1. void bar(Foo &f)
  2. {
  3.     f.do_something(); // essaye d'appeler la mauvaise ...   
  4. }


transforme le passage par référence en passage par copie, et voilà.


 
au contraire. Le comportement polymorphique va disparaitre.


On est d'accord, ce qui permet d'appeler la mauvaise :) Un simple oublie fait sauter la "protection". Manquerait une fonction virtuelle pure par exemple pour empêcher cela.
 
Je suis aussi d'accord qu'on manque d'éléments pour répondre.


---------------
FAQ fclc++ - FAQ C++ - C++ FAQ Lite
Reply

Marsh Posté le 08-10-2005 à 14:50:17    

Citation :

On est d'accord, ce qui permet d'appeler la mauvaise :) Un simple oublie fait sauter la "protection". Manquerait une fonction virtuelle pure par exemple pour empêcher cela.


 
yep ! Le probleme, c'est que la classe Foo devait rester instanciable dans l'exemple ...
On se heurte aux inconvénients de faire un héritage public d'une classe concrète, et d'overrider des fonctions virtuelles.
Avec une classe FooBase de laquelle héritent publiquement Foo et LockedFoo, le probleme disparait, quitte à définir un destructeur virtuel pur dans FooBase.

Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed