IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++ Discussion :

Méthodes virtuelles - Cas à éviter ?


Sujet :

C++

  1. #1
    Membre averti
    Profil pro
    Étudiant
    Inscrit en
    Août 2006
    Messages
    59
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Août 2006
    Messages : 59
    Par défaut Méthodes virtuelles - Cas à éviter ?
    Bonjour.
    J'aimerais savoir s'il existe des cas où une méthode virtuelle est à rejetée. Bien que certaines méthodes de mon programme ne seront en principe jamais redéfinies, j'ai pris l'habitude de déclarer toutes les méthodes comme virtuelles. Au cas où.

    Est-ce une mauvaise idée ?
    Existe-t-il des cas où les méthodes virtuelles empêchent le bon fonctionnement de la classe ?
    Y a-t-il une perte de performance ?
    Bref, est-ce que cela affecte l'exécutable d'une quelconque manière ?

    Merci d'avance !

    Edit: Je viens par pur hasard de tomber sur un cas où les méthodes virtuelles ne fonctionnent pas (bien que ce soit un peu hors sujet):
    Lors d'un appel du constructeur de la classe mère, s'il y a appel à une méthode virtuelle dans celui ci, la méthode de la classe mère sera appelée, et non celle de la classe fille. Ceci est du au fait que la classe fille n'est pas encore construite à ce moment.

  2. #2
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    8
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2008
    Messages : 8
    Par défaut
    Bonjour nuks

    Une méthode devrait être déclarer virtuelle lorsque les deux conditions suivantes sont remplies:

    1) Elle est redéfinie par une classe dérivée.
    2) Elle est appelée par une méthode de la classe de base.

    Si l'une des conditions n'est pas remplie, il est inutile de déclarer la méthode virtuelle. (tout simplement, si la méthode n'est pas redéfinie par une classe dérivée, il est clair que la méthode n'a pas besoin d'être virtuelle)

    Si 1) est remplie mais pas 2), alors une substitution simple suffira pour la classe dérivée.

    Mais pourquoi tout ce tralalala!

    Imaginons les classes suivantes:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    class Animal {
        char nom[45], espece[45];
     
    protected:
        Animal(char *nom, char *espece);
        ~Animal();
     
    public:
        virtual void naissance();
        void elevage(); //la méthode qui appellera naissance pour la condition 2)
    };
     
     
    class Chien {
     
    public:
        Chien(char *nom);
    };
     
    class Poule {
     
    public:
        Poule(char *nom);
        void naissance();
    };
    Et le code suivant:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    main() {
        Chien chien("Toutou");
        Poule poule("Chicken Little");
        chien.elevage(); //naissance() est appelé depuis Animal
        poule.elevage(); //naissance() est appelé depuis Poule
    }
    Ainsi lorsque la méthode elevage est appelée en passant par l'instance de la classe Poule, le programme appellera la méthode elevage de la classe de base qui appellera la méthode naissance. Mais comme la méthode naissance est virtuelle, ce ne sera pas celle de la classe de base qui sera utilisé mais celle de Poule.

    Une méthode virtuelle permet en fait au programme d'effectuer un chaînage de méthode dynamique.

    Si tu enlève le virtual, tu remarqueras que ce chaînage dynamique ne s'effectuera plus et que la ligne suivante:

    n'appellera plus la méthode naissance redéfinie par Poule mais bien celle de la classe de base, soit Animal.

    Bel exemple de polymorphisme...

  3. #3
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    8
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2008
    Messages : 8
    Par défaut
    Citation Envoyé par nuKs Voir le message
    ....j'ai pris l'habitude de déclarer toutes les méthodes comme virtuelles. Au cas où.

    Est-ce une mauvaise idée ?
    1. OUI!!

    Citation Envoyé par nuKs Voir le message
    Existe-t-il des cas où les méthodes virtuelles empêchent le bon fonctionnement de la classe ?
    2. Si tu comprend bien l'exemple, tu peux voir les ennuis que cela peut te générer...(mauvaise méthode appelé, etc..)

    Citation Envoyé par nuKs Voir le message
    Y a-t-il une perte de performance ?
    3. 2) te donnent une idée...

    Citation Envoyé par nuKs Voir le message
    Bref, est-ce que cela affecte l'exécutable d'une quelconque manière ?
    4. 1) 2) et 3)

  4. #4
    Membre averti
    Profil pro
    Étudiant
    Inscrit en
    Août 2006
    Messages
    59
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Août 2006
    Messages : 59
    Par défaut
    Tout d'abord, merci de ta réponse ;-)
    Je me permet d'ajouter (en espérant ne pas me tromper) le cas où l'on utilise un pointeur de la classe mère qui pointe vers la classe fille. Si la méthode appelée n'est pas virtuelle, la méthode appelée sera celle de la classe mère et non de la classe fille.

    Donc si j'ai bien compris, le fait de déclarer une méthode virtuelle (qui ne devrait pas l'être) pourrait causer un sérieux ennui si l'on veut appeler sa "version" de la classe mère et qu'on se trouve dans une classe fille.

    C'est un cas extrêmement rare, et j'ai pris l'habitude, dans cette situation, de toujours déclarer explicitement la classe mère quand je voulais utiliser une de ses méthodes Ca expliquerait pourquoi ça ne m'a jamais poser de problème. Toutefois, la situation risque donc de dégénérer si le code de la classe fille ne vient pas de moi.

    Le problème serait surtout de savoir qu'elle méthode de la classe mère ne sera donc pas redéfinie dans la classe fille et sera utiliser par une méthode de cette classe fille. Ca risque de me demander un petit temps de réflexion pour chaque méthodes :/

  5. #5
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut
    Bonjour,
    Déclarer toutes ses méthodes comme virtuelles n'est pas à prescrire. La raison fondamentale est que cela traduit un gros défaut de conception. C'est que tu ne sais pas définir la responsabilité de ta classe.
    Accessoirement, tu auras une chute drastique des performances.

  6. #6
    Membre émérite
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    1 064
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2005
    Messages : 1 064
    Par défaut
    Écoute, c'est bien simple. Les méthodes virtuelles servent à faire du polymorphisme objet en C++. Si tu ne fais pas de polymorphisme objet les utiliser ne t'apportera qu'une perte de performance inutile.
    Au fait, même si je ne devrais pas avoir à l'expliquer, contrairement à d'autres langages comme le C#, faire du polymorphisme objet en C++ ne revient pas simplement à ajouter un mot clé virtual à coté des méthodes.
    Néanmoins pour les classes n'étant utilisées que de manière polymorphe déclarer toutes les méthodes virtuelles est parfaitement valide.

  7. #7
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut
    Citation Envoyé par zais_ethael Voir le message
    Néanmoins pour les classes n'étant utilisées que de manière polymorphe déclarer toutes les méthodes virtuelles est parfaitement valide.
    C'est valide mais j'ai jamais vu le cas. Pour moi, si tu tombes dans ce cas, ça doit faire tilt au niveau de la conception.

  8. #8
    Membre averti
    Profil pro
    Étudiant
    Inscrit en
    Août 2006
    Messages
    59
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Août 2006
    Messages : 59
    Par défaut
    Merci à tous pour vos réponses. Tout est ok.

  9. #9
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Par défaut
    Il y a un conseil de codage qui suggère qui dit qu'une fonction membre à la fois publique est virtuelle est une mauvaise idée. Elle fait trop de choses, car elle sert d'interface pour l'utilisateur de la classe (publique) et pour la personne qui veut particulariser le comportement (virtuel). C'est par exemple dans la fonction publique non virtuelle que l'on placera la vérification des invariants ou de l'instrumentation de code.

    Je n'ai pas à me plaindre de ce conseil depuis que je le suis.

    Voir aussi http://www.gotw.ca/publications/mill18.htm
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  10. #10
    Membre émérite
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    1 064
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2005
    Messages : 1 064
    Par défaut
    Citation Envoyé par 3DArchi Voir le message
    C'est valide mais j'ai jamais vu le cas. Pour moi, si tu tombes dans ce cas, ça doit faire tilt au niveau de la conception.
    Ben, et pour les interfaces alors?

    @Loic: Tu ne serais pas en train de parler du design pattern template method? Si c'est le cas, faut quand même pas généraliser. Tout n'est pas applicable à ce pattern et il est facile de transformer un tel design vers un système utilisant des interfaces ou encore de la méta programmation.

  11. #11
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Par défaut
    Citation Envoyé par zais_ethael Voir le message
    @Loic: Tu ne serais pas en train de parler du design pattern template method?
    Pas vraiment. Ca peut y ressembler dans la forme, mais les objectifs sont différents.

    C'est plus une façon d'écrire du design-by-contract en C++. Au lieu d'avoir :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    public:
      virtual void f();
    On a :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    public:
      void f()
      {
        // Vérifier les préconditions
        doF();
        // Vérivier les post-condition
      }
    private:
      virtual void doF(); // souvent = 0
      {
      }
    Avoir un point unique et invariable pour instrumenter le code me semble un plus contrebalaçant le fait d'avoir une fonction de plus.
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  12. #12
    Membre averti
    Profil pro
    Étudiant
    Inscrit en
    Août 2006
    Messages
    59
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Août 2006
    Messages : 59
    Par défaut
    JolyLoic> Merci pour le tips, je note.

    Au cas où ça intéresserait quelqu'un passant par là, après avoir lus vos réponse, je me suis poser une question: pourquoi un destructeur doit-il toujours être virtuel (je l'ai lus tellement de fois) ? La réponse est simple. Le destructeur ne doit pas toujours être virtuel. Je cite (source: http://h-deb.clg.qc.ca/Sujets/TrucsS...s-quand.html):
    Ainsi, dans une classe donnée, on ne spécifie un destructeur virtuel que si cette classe a au moins une autre méthode virtuelle. Si une classe n'expose aucune méthode virtuelle, alors elle ne peut servir d'abstraction polymorphique et un destructeur virtuel ne servirait qu'à grossir et à ralentir la classe.

  13. #13
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 397
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 397
    Par défaut
    Sur gotw, ils recommandent qu'un destructeur de classe mère soit soit public et virtuel, soit protected et non-virtuel.

    Un destructeur protected non-virtuel dans la classe parente montre que cette classe n'est pas destinée à être détruite de manière polymorphique.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  14. #14
    Expert confirmé
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 296
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Août 2003
    Messages : 5 296
    Par défaut
    Je copie-colle un petit pavé que j'avais pondu ailleurs:

    Citation Envoyé par moi même
    Une école tend à définir toutes les fonctions en virtuel : « mettons la fonction en virtuel, quelqu'un pourrait vouloir la supplanter ». Seulement...

    Si une fonction ne correspond pas à un point de variation [Coplien1998] prévu lors de la conception, il reste peu probable que l'on puisse étendre le système simplement parce que la fonction était virtuelle. Bien souvent, rajouter correctement un point de variation non initialement prévu demande un refactoring non trivial du code, c'est à dire bien plus qu'ajouter un simple "virtual".

    Bien sûr, plus les fonctions d'une classe respectent le principe, « Une fonction doit faire une chose, et doit le faire bien » (aka les fonctions doivent être courtes, avec peu de niveaux d'imbrications, ...), plus il est simple d'introduire des points de variations à la volée. Seulement si toutes sont virtuelles, cela veut aussi dire que toutes ces fonctions membre (en nombre plus ou moins important) peuvent être supplantées. Les classes filles auraient alors une visibilité complète de la classe mère. De cette rupture d'encapsulation inter-générations, il devient alors vite complexe de savoir ce qui peut être supplanté, et sous quelles conditions (contraintes).

    De plus, les hiérarchies polymorphes ayant naturellement une sémantique d'entité, définir virtuelle une quelconque fonction membre d'une classe à sémantique de valeur n'a aucun sens. C'est aussi pour cela qu'aucun conteneur de la bibliothèque standard ne dispose de fonction membre virtuelle.

    Enfin, virtual introduit un sur-coût lors d'un appel de fonction où il n'était pas nécessaire. De fait, pour des raisons d'optimisation, on évite également de payer inutilement pour un service dont on n'a pas besoin : à savoir un branchement conditionnel déterminé à l'exécution (NB: il n'y aucune différence de rapidité, voire de meilleures performances sont à attendre de virtual par rapport à des if en chaîne, un switch-case, des tables d'indirection, etc.).
    PS: dans le lexique de son livre, Stroustrup assimile "méthode" à "fonction membre virtuelle".
    Blog|FAQ C++|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS|Bons livres sur le C++
    Les MP ne sont pas une hotline. Je ne réponds à aucune question technique par le biais de ce média. Et de toutes façons, ma BAL sur dvpz est pleine...

  15. #15
    Expert confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Décembre 2003
    Messages
    3 549
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Décembre 2003
    Messages : 3 549
    Par défaut
    (NB: il n'y aucune différence de rapidité, voire de meilleures performances sont à attendre de virtual par rapport à des if en chaîne, un switch-case, des tables d'indirection, etc.).
    Si il y a une différence, un switch c'est plus rapide.

  16. #16
    Membre émérite
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    1 064
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2005
    Messages : 1 064
    Par défaut
    Citation Envoyé par JolyLoic Voir le message
    Avoir un point unique et invariable pour instrumenter le code me semble un plus contrebalaçant le fait d'avoir une fonction de plus.
    Moi je ferais la même chose mais exprimée autrement:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    class claz {
    interface* inter;
    public:
    void f() {
       // ...
       int->f();
       // ...
    }
    };
     
    struct interface {
       virtual void f() =0;
    };
    Pourquoi? Parce que la plupart du temps quand j'utilise du polymorphisme objet c'est pour customiser certains aspects d'un algorithme plus complexe, les méthodes que j'appelerais de l'extérieur ne sont pas forcément un reflet des méthodes appelées sur mon objet polymorphe. Redéfinir quelques méthodes dans une classe fille est parfois insuffisant (que faire si on doit gérer une liste ou une map d'objets polymorphes?) et parfois peu explicite (p.e. si certains aspects sont facultatifs). Ou encore on peut vouloir faire varier l'implémentation de ces aspects à l'exécution (ce qui est toujours le cas, sinon on utiliserait du polymorphisme via templates) sans altérer le reste des variables utilisées par l'algorithme.

    En C++ plus précisément ça permet aussi d'encapsuler cette saleté de gestion de cycle de vie qu'ont la plupart des objets polymorphes et de récupérer une sémantique par valeur dans le reste du code.

  17. #17
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Par défaut
    Citation Envoyé par zais_ethael Voir le message
    Redéfinir quelques méthodes dans une classe fille est parfois insuffisant (que faire si on doit gérer une liste ou une map d'objets polymorphes?) et parfois peu explicite (p.e. si certains aspects sont facultatifs).
    Je n'ai pas compris ce que tu voulais dire là.
    Citation Envoyé par zais_ethael Voir le message
    En C++ plus précisément ça permet aussi d'encapsuler cette saleté de gestion de cycle de vie qu'ont la plupart des objets polymorphes et de récupérer une sémantique par valeur dans le reste du code.
    Pour ça, dans mon cas, j'utilise plutôt les smart ptrs appropriés. Ce qui permet d'avoir plusieurs types de gestion de durée de vie pour une seule classe, ce que ton mode de fonctionnement ne permet pas.
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  18. #18
    Membre émérite
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    1 064
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2005
    Messages : 1 064
    Par défaut
    Citation Envoyé par JolyLoic Voir le message
    Je n'ai pas compris ce que tu voulais dire là.
    Par exemple, imaginons un gestionnaire d'évènement style jeux vidéo:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    class event_manager {
    unordered_map<type_of_event,event_handler*> mappings;
    void handle_event() {
       for(event in events){
          mappings[event].handle();
       }
    }
    };
    En créant des sous-classes de event_manager il aurait fallu, par exemple, rendre la méthode handle_event() abstraite, ce qui aurait alors nécessité de déléguer la logique de sélection du event_handler à la classe fille. On aurait pas non plus la possibilité de modifier juste une partie de la map des event_handlers, il faudrait complétement permuter d'une instance de event_manager à une autre.

Discussions similaires

  1. Appel d'une méthode virtuelles
    Par BIPBIP59 dans le forum C++Builder
    Réponses: 4
    Dernier message: 24/03/2006, 14h00
  2. Méthodes virtuelle et implémentation
    Par slate dans le forum C++
    Réponses: 2
    Dernier message: 16/02/2006, 17h16
  3. méthodes virtuelles
    Par ep31 dans le forum C++
    Réponses: 2
    Dernier message: 09/11/2005, 17h21
  4. Comment l'appel à une méthode virtuelle....
    Par Blobette dans le forum C++
    Réponses: 7
    Dernier message: 07/12/2004, 13h55
  5. [C#] Méthode virtuelle
    Par jacma dans le forum Windows Forms
    Réponses: 4
    Dernier message: 07/11/2004, 08h18

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo