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 :

Classe virtuelle pure


Sujet :

C++

  1. #21
    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
    Points : 13 017
    Points
    13 017
    Par défaut
    Salut,
    Citation Envoyé par oodini Voir le message
    J'ajouterai qu'il est possible de déclarer une méthode virtuelle comme étant pure (= 0) tout en fournissant une implémentation, utilisable une fois qu'on aura rendu l'instanciation possible dans une classe dérivée.

    Pervers, certes..
    La définition d'une fonction virtuelle pure dans une classe abstraite ne sera jamais exécutée par une résolution dynamique d'un appel. Elle nécessite forcément un appel explicite. Je n'ai pas souvenir d'un cas concret où cela avait un intérêt.
    cf XI-B. Appel d'une fonction virtuelle pure

  2. #22
    En attente de confirmation mail

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France, Doubs (Franche Comté)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Points : 3 311
    Points
    3 311
    Par défaut
    Je suis assez d'accord avec 3DArchi, au cas du destructeur près (là la définition du destructeur virtuelle pure est appelé automatiquement lors de la destruction des objets d'un sous-type), et à part cette utilisation du destructeur pour rendre une classe abstraite quand il n'y a pas d'autre fonctions qui pourraient l'être je ne vois pas d'autre cas d'utilisation.

    Meyers en donne une dans Eff++ : donner à l'utilisateur de la classe la possibilité d'avoir un comportement par défaut à utiliser si il ne sait pas/n'a rien à mettre lors de la redéfinition dans une classe fille, cependant je ne suis pas convaincu de l'utilité pratique de cette utilisation, si on peut définir un comportement par défaut alors pourquoi ne pas mettre la fonction simplement virtuelle ? Pour rappeler à l'utilisateur que ce comportement par défaut est juste une porte de sortie et qu'il aurait du redéfinir cette fonction ? Je trouve que ca risque plus facilement d'embrouiller l'utilisateur de la classe qu'autre chose dans ce cas.

  3. #23
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 630
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 630
    Points : 30 699
    Points
    30 699
    Par défaut
    Citation Envoyé par Flob90 Voir le message
    Meyers en donne une dans Eff++ : donner à l'utilisateur de la classe la possibilité d'avoir un comportement par défaut à utiliser si il ne sait pas/n'a rien à mettre lors de la redéfinition dans une classe fille, cependant je ne suis pas convaincu de l'utilité pratique de cette utilisation, si on peut définir un comportement par défaut alors pourquoi ne pas mettre la fonction simplement virtuelle ? Pour rappeler à l'utilisateur que ce comportement par défaut est juste une porte de sortie et qu'il aurait du redéfinir cette fonction ? Je trouve que ca risque plus facilement d'embrouiller l'utilisateur de la classe qu'autre chose dans ce cas.
    Tout dépend du comportement que tu fournis par défaut et de ce qui entoure la fonction virtuelle pure définie ...

    Je m'explique : imaginons trente secondes que nous ayions effectivement une classe de base qui ait vocation à être abstraite, mais dont on a défini le destructeur de manière non virtuelle et protégée (parce que la durée de vie des objets concrets est gérée sous forme d'objets et non sous la forme de la classe dérivée).

    Le destructeur n'a aucun intérêt à être virtuel, et il est donc impossible de le rendre virtuel pur!

    Mais s'il est possible de fournir un comportement par défaut à l'ensemble des fonctions de la classe de base (y compris aux fonctions virtuelles), il faut bien trouver une fonction discriminante qui permette de rendre la classe abstraite!

    Finalement, le fait de forcer l'utilisateur à redéfinir cette fonction n'est qu'un "effet secondaire" de la nécessité de rendre la classe de base abstraite

    Je suis d'accord que cela mérite d'être largement commenté (du genre : virtuelle pure pour garder la classe abstraite, mais si vous ne savez pas quoi faire pour la ré-implémenter, invoquez Base::laFonction, cela devrait aller ), mais cela peut être la seule solution pour concilier l'inconciliable

  4. #24
    En attente de confirmation mail

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France, Doubs (Franche Comté)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Points : 3 311
    Points
    3 311
    Par défaut
    Tu ne veux pas passer le destructeur en virtuelle pure (protégé) dans ce cas pour éviter que l'ajout d'un pointeur dans la vtable et une indirection lors de l'appel des destructeur ? Le gain apporté est significatif ?

    Ne peut-on pas aussi mettre les constructeurs en protégé comme solution alternative ?

  5. #25
    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
    Points : 13 017
    Points
    13 017
    Par défaut
    @flob : effectivement, mon précédent msg ne concernait pas le destructeur qui est un cas particulier.

    @Koala : je ne suis pas d'accord avec toi. Je préfère un destructeur virtuel pur en protégé que rendre artificiellement une des fonctions virtuelles pures. Le fait d'avoir à l'appeler explicitement me dérange.

  6. #26
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 630
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 630
    Points : 30 699
    Points
    30 699
    Par défaut
    Citation Envoyé par 3DArchi Voir le message
    @flob : effectivement, mon précédent msg ne concernait pas le destructeur qui est un cas particulier.

    @Koala : je ne suis pas d'accord avec toi. Je préfère un destructeur virtuel pur en protégé que rendre artificiellement une des fonctions virtuelles pures. Le fait d'avoir à l'appeler explicitement me dérange.
    Bah, ce n'est peut etre pas forcément idéal, mais, par contre, cela a l'énorme avantage d'attirer l'attention de l'utilisateur sur le fait qu'il est sans doute préférable de réfléchir au comportement qui sera réellement adapté pour cette fonction.

    C'est un peu comme dire à l'utilisateur
    voilà, je fournis un comportement par défaut qui, au moins, ne fait pas d'erreur, mais qui n'est sans doute pas adapté à votre classe dérivée
    Le message d'erreur deu compilateur aidant (impossible de créer une instance de la classe machin parce que la fonction faitCeci est virtuelle pure) l'utilisateur a réellement toutes les informations pour être en mesure de décider si, oui ou non, le comportement par défaut est adapté

    Je suis d'accord que c'est tiré par les cheveux, que c'est sans doute un peu vicieux, mais ce n'est pas forcément dérangeant

  7. #27
    En attente de confirmation mail

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France, Doubs (Franche Comté)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Points : 3 311
    Points
    3 311
    Par défaut
    Citation Envoyé par koala01 Voir le message
    C'est un peu comme dire à l'utilisateur Le message d'erreur deu compilateur aidant (impossible de créer une instance de la classe machin parce que la fonction faitCeci est virtuelle pure) l'utilisateur a réellement toutes les informations pour être en mesure de décider si, oui ou non, le comportement par défaut est adapté
    Oui, c'est ce que j'entendais par :

    Pour rappeler à l'utilisateur que ce comportement par défaut est juste une porte de sortie et qu'il aurait du redéfinir cette fonction ?
    Mais comme tu l'as signalé, il faut quand même que ce soit clairement dit sinon l'utilisateur de la classe risque d'être perdue, et c'est ce qui me fait penser que ca ne doit pas être une pratique usuel : en général on essaie de rendre les choses user-friendly, pas d'utiliser une syntaxe valide mais peu utilisé qui demande à l'utilisateur d'adapter ses habitudes de programmation.

  8. #28
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 630
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 630
    Points : 30 699
    Points
    30 699
    Par défaut
    Citation Envoyé par Flob90 Voir le message
    Mais comme tu l'as signalé, il faut quand même que ce soit clairement dit sinon l'utilisateur de la classe risque d'être perdue, et c'est ce qui me fait penser que ca ne doit pas être une pratique usuel : en général on essaie de rendre les choses user-friendly, pas d'utiliser une syntaxe valide mais peu utilisé qui demande à l'utilisateur d'adapter ses habitudes de programmation.
    Mais c'est peut etre le seul moyen de concilier l'inconciliable...

    Le destructeur protégé (virtuel ou non) ne garanti pas la non instanciabilité de la classe de base : il ne fait que garantir la non destructabilité des objets lorsqu'ils sont considérés comme étant du type de base

    Même le fait de déclarer le reste du big four (opérateur d'affectation, constructeur par copie et constructeurs (prenant ou non des arguments) ) comme protégé n'empêche pas l'instanciation de la classe... Cela ne fait que rendre les choses un peu plus compliquées, mais il suffit d'une amitié mal gérée ou d'un
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    class Derived : public Base
    {
        public:
            Base * truc(){return new Base;}
    };
    pour se retrouver avec une instance de la classe de base qui n'est d'aucun type dérivé

    La classe abstraite, et au travers d'elle, la fonction virtuelle pure, est, définitivement, la seule solution garantissant la non instanciabilité d'une (hiérarchie de) classe(s).

    Si cette contrainte est vraiment forte (pour raison de spécifications), il peut devenir presque logique rendre une fonction virtuelle pure tout en lui donnant un comportement

  9. #29
    En attente de confirmation mail

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France, Doubs (Franche Comté)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Points : 3 311
    Points
    3 311
    Par défaut
    Si le destructeur est virtuelle pure et protégé ca garantie aussi les deux, pour ca que je ne comprends pas pourquoi ne pas utiliser cette solution ?

    Non, si le big four est protégé, la seul solution (que je vois) c'est une fonction amie de la classe de base, c'est moins fort qu'une classe abstraite mais ca reste un risque assez maitrisé je trouve. (Du point de vue de l'utilisateur (*) la protection est la même, par contre du point de vue du développeur la classe abstraite te protège de créer involontairement une instance).

    Pour reprendre l'idée de code que tu proposes :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    template<class T>
    struct UseCtor : private T
    { static T* process()
     { return new T(); } };
    Ne compile pas (à l'utilisation).

    Mais je suis d'accord avec toi, c'est la seule garantie totale de ne pouvoir créer un objet de ce type uniquement comme sous-objet Mais si j'en ai besoin je peserais quand même le pour et le contre entre les différentes solutions.

    (*) Sauf si tu laisses à l'utilisateur le soin d'implémenter les fonctions amies et membres de la classe de base ...

  10. #30
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 630
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 630
    Points : 30 699
    Points
    30 699
    Par défaut
    Citation Envoyé par Flob90 Voir le message
    Si le destructeur est virtuelle pure et protégé ca garantie aussi les deux, pour ca que je ne comprends pas pourquoi ne pas utiliser cette solution ?
    Non!!!

    Il faudrait au minimum que le destructeur soit virtuel pur (quel que soit sa visibilité) pour qu'il puisse garantir quoi que ce soit au niveau de l'instanciabilité de la classe


    Si le destructeur est protégé, tout ce qu'il peut garantir, c'est que les objets passant pour être du type de la classe de base ne pourront pas être détruit tant que l'on n'aura pas déterminé exactement quel est leur type dynamique

    Non, si le big four est protégé, la seul solution (que je vois) c'est une fonction amie de la classe de base,
    Ou n'importe quelle classe dérivée, car les (fonctions) membres protégés sont accessibles à toutes les classes enfants (et à leur dérivées)
    c'est moins fort qu'une classe abstraite mais ca reste un risque assez maitrisé je trouve. (Du point de vue de l'utilisateur (*) la protection est la même, par contre du point de vue du développeur la classe abstraite te protège de créer involontairement une instance).
    Disons que la classe abstraite est la seule solution garantie "100% idiot proof" permettant d'assurer la non instanciabilité d'une classe.

    Toute autre solution peut, certes, apporter un "certain niveau" de garantie, mais restera malgré tout contournable (la classe dérivée qui fait un new base en est un exemple, l'amitié mal gérée également )
    Pour reprendre l'idée de code que tu proposes :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    template<class T>
    struct UseCtor : private T
    { static T* process()
     { return new T(); } };
    Ne compile pas (à l'utilisation).
    Sauf que tu changes les règles en partant sur un héritage privé, alors que j'ai chaque fois bien pris la précaution de préciser héritage public, c'est à dire une relation EST-UN, et non une relation EST IMPLEMENTEE EN TERME DE
    Mais je suis d'accord avec toi, c'est la seule garantie totale de ne pouvoir créer un objet de ce type uniquement comme sous-objet Mais si j'en ai besoin je peserais quand même le pour et le contre entre les différentes solutions.
    (*) Sauf si tu laisses à l'utilisateur le soin d'implémenter les fonctions amies et membres de la classe de base ...
    Non, cela va beaucoup plus loin, car toute classe dérivant publiquement de manière directe ou indirecte de la classe de base pour laquelle tu aurais déclaré le big four en protégé est susceptible de créer une instance de la classe de base.

    Or, tu peux, éventuellement, garder un oeil sur ce que toi tu fais, mais, si ta classe est destinée à être utilisée par d'autres, tu ne peux rien garantir à leur niveau

  11. #31
    En attente de confirmation mail

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France, Doubs (Franche Comté)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Points : 3 311
    Points
    3 311
    Par défaut
    J'ai bien écrit virtuel pur (avec des fautes mais quand même) ...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    template<class T>
    struct UseCtor : T
    {
    	T* process()
    	{ return new T(); }
    };
    Compile pas mieux (toujours à l'utilisation).

    Non, cela va beaucoup plus loin, car toute classe dérivant publiquement de manière directe ou indirecte de la classe de base pour laquelle tu aurais déclaré le big four en protégé est susceptible de créer une instance de la classe de base.
    Donnes moi un exemple (autre que les fonctions membres et amies de la classe de base), parce que je n'en vois aucun.

    Ou n'importe quelle classe dérivée, car les (fonctions) membres protégés sont accessibles à toutes les classes enfants (et à leur dérivées)
    C'est pas exactement ca l'accessiblité protégé. Tu peux accéder (au sein de la classe fille, scope et fonctions membres et amies) aux fonctions membres statiques héritées en accessibilité protégé, et accéder aux membres (fonctions ou non) héritées en accessibilité protégé sur des objets du type statique celui de la fille (et le mode d"héritage ne change rien à ca).

    Ca exclut les constructeurs de la manière dont tu veux l'utiliser (on peut y accéder pour construire le sous-objet par contre).

  12. #32
    Membre émérite
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 764
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 764
    Points : 2 705
    Points
    2 705
    Par défaut
    Qu'il est beau de voir se dérouler un pugilat intellectuel parce que j'ai mis mon grain de poivre...

Discussions similaires

  1. Boost, serialisation et classe virtuelle pure.
    Par AF_2.8 dans le forum Boost
    Réponses: 3
    Dernier message: 06/12/2010, 11h14
  2. question sur les classes virtuelles pures
    Par deubelte dans le forum C++
    Réponses: 5
    Dernier message: 26/07/2010, 17h45
  3. aide classe virtuel pure
    Par wasdaka dans le forum C++
    Réponses: 2
    Dernier message: 20/04/2009, 23h21
  4. Réponses: 2
    Dernier message: 18/02/2009, 09h29
  5. Réponses: 8
    Dernier message: 16/10/2006, 13h28

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