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

Langage C++ Discussion :

Proposition : héritage constant


Sujet :

Langage C++

  1. #1
    Expert éminent
    Avatar de Pyramidev
    Homme Profil pro
    Développeur
    Inscrit en
    Avril 2016
    Messages
    1 470
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur

    Informations forums :
    Inscription : Avril 2016
    Messages : 1 470
    Points : 6 107
    Points
    6 107
    Par défaut Proposition : héritage constant
    Bonjour,

    Que pensez-vous de l'idée d'un héritage constant en C++ ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    class Cercle : public const EllipseAbstraite { /*...*/ };
    Caractéristiques :
    • Cercle& est convertible en const EllipseAbstraite&, mais pas en EllipseAbstraite&.
    • Si EllipseAbstraite a des fonctions virtuelles pures alors, pour que Cercle soit instanciable, il doit implémenter les fonctions virtuelles pures constantes de EllipseAbstraite.
    • Si on appelle une fonction non constante de EllipseAbstraite via une instance de Cercle (à cause d'un const_cast), le comportement est indéterminé.
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      1
      2
      3
      4
      5
      Cercle cercle;
      const EllipseAbstraite& ellipse = cercle;;
      EllipseAbstraite& danger = const_cast<EllipseAbstraite&>(ellipse);
      danger.fonctionNonConstante(); // aïe
      danger.fonctionVirtuellePureNonConstante(); // crash
    • Le code suivant est autorisé :
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      1
      2
      class Deriv : virtual public const Base { /*...*/ };
      class Deriv2 : public Deriv, virtual public Base { /*...*/ }; // pas de const
    • Pour la cohérence, on aurait aussi l'héritage volatile et l'héritage constant volatile, qui ne serviraient à rien.


    Le principal intérêt serait de réduire la quantité de classes en évitant les doublons Base/ConstBase :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    class EllipseAbstraite : public ConstEllipseAbstraite { /*...*/ };
    class Cercle           : public ConstEllipseAbstraite { /*...*/ };

  2. #2
    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 : 49
    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
    Points : 16 213
    Points
    16 213
    Par défaut
    Avant de détailler le mécanisme plus en détails, tu pourrais détailler la motivation ? Parce que pour l'instant, je ne vois pas trop ce qu'on y gagne...
    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.

  3. #3
    Expert éminent
    Avatar de Pyramidev
    Homme Profil pro
    Développeur
    Inscrit en
    Avril 2016
    Messages
    1 470
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur

    Informations forums :
    Inscription : Avril 2016
    Messages : 1 470
    Points : 6 107
    Points
    6 107
    Par défaut
    Par exemple, à la place de ceci :
    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
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    class Product { /*...*/ };
    class Fruit : public Product { /*...*/ };
    class Orange : public Fruit { /*...*/ };
     
    class ConstProductTable {
    public:
        virtual const Product& getProduct(size_t index) const = 0;
        // ...
    };
     
    class ProductTable : public ConstProductTable {
    public:
        virtual void addProduct(const Product&) = 0;
        // ...
    };
     
    class ConstFruitTable : public ConstProductTable {
    public:
        const Fruit& getProduct(size_t index) const override = 0;
        // ...
    };
     
    class FruitTable : public ConstFruitTable {
    public:
        virtual void addFruit(const Fruit&) = 0;
        // ...
    };
     
    class ConstOrangeTable : public ConstFruitTable {
    public:
        const Orange& getProduct(size_t index) const override = 0;
        // ...
    };
     
    class OrangeTable : public ConstOrangeTable {
    public:
        virtual void addOrange(const Orange&) = 0;
        // ...
    };
    On aurait cela :
    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
    class Product { /*...*/ };
    class Fruit : public Product { /*...*/ };
    class Orange : public Fruit { /*...*/ };
     
    class ProductTable {
    public:
        virtual const Product& getProduct(size_t index) const = 0;
        virtual void addProduct(const Product&) = 0;
        // ...
    };
     
    class FruitTable : public const ProductTable {
    public:
        const Fruit& getProduct(size_t index) const override = 0;
        virtual void addFruit(const Fruit&) = 0;
        // ...
    };
     
    class OrangeTable : public const FruitTable {
    public:
        const Orange& getProduct(size_t index) const override = 0;
        virtual void addOrange(const Orange&) = 0;
        // ...
    };
    Edit 2016-12-19-19h52 (après la réponse de JolyLoic) : J'avais oublié de rendre pures mes fonctions virtuelles.

  4. #4
    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 : 49
    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
    Points : 16 213
    Points
    16 213
    Par défaut
    Et comment implémentes-tu FruitTable::addFruit ?
    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.

  5. #5
    Expert éminent
    Avatar de Pyramidev
    Homme Profil pro
    Développeur
    Inscrit en
    Avril 2016
    Messages
    1 470
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur

    Informations forums :
    Inscription : Avril 2016
    Messages : 1 470
    Points : 6 107
    Points
    6 107
    Par défaut
    Oups. J'ai oublié de rendre pures les fonctions virtuelles de mon précédent message.
    Code modifié et factorisé :
    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
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    class Product {
    	// ...
    };
     
    class Fruit : public Product {
    public:
    	using base = Product;
    	// ...
    };
     
    class Orange : public Fruit {
    public:
    	using base = Fruit;
    	// ...
    };
     
    template<class T>
    class ProductTable;
     
    template<>
    class ProductTable<Product> {
    public:
        virtual const Product& getProduct(size_t index) const = 0;
        virtual void append(const Product&) = 0;
        // ...
    };
     
    template<class T>
    class ProductTable : public const ProductTable<typename T::base> {
    public:
        const T& getProduct(size_t index) const override = 0;
        virtual void append(const T&) = 0;
        // ...
    };
     
    class ConcreteOrangeTable : public ProductTable<Orange> {
    public:
        const Orange& getProduct(size_t index) const override;
        void append(const Orange&) override;
        // ...
    };
    Dans mon exemple, ConcreteOrangeTable& serait convertible en ProductTable<Orange>, en const ProductTable<Fruit>& et en const ProductTable<Product>&.

  6. #6
    Expert éminent
    Avatar de Pyramidev
    Homme Profil pro
    Développeur
    Inscrit en
    Avril 2016
    Messages
    1 470
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur

    Informations forums :
    Inscription : Avril 2016
    Messages : 1 470
    Points : 6 107
    Points
    6 107
    Par défaut
    Aucun avis ?

    Personnellement, je suis partagé.
    D'un côté, cela permettrait de réduire le nombre de classes dans des cas assez rares.
    De l'autre, cela complexifierait un peu plus le langage C++ qui est déjà compliqué.

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Salut,

    A mon avis, cela ne servirait à rien : Si les classes qui interviennent dans la hiérarchie n'exposent que des fonctions membres déclarées comme étant constantes (n'oublie pas que le principe de conception d'une classe est de s'intéresser aux services qu'elle peut rendre avant de s'intéresser aux données qu'elle contient ), même si l'objet ("final" ou "intermédiaire") est considéré comme non constant, les services exposés ne permettront de toutes manières pas de modifier le dit objet, et le problème sera résolu d'office

    Le seul truc, c'est qu'il faut bel et bien penser aux services que doi(ven)t rendre ta (tes) classe(s) avant de réfléchir aux données qui lui (leur) permettront de rendre ces services, au lieu de penser aux données que l'on estime nécessaires au niveau de la classe avant de penser à la manière dont ces données seront manipulées
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  8. #8
    Expert éminent
    Avatar de Pyramidev
    Homme Profil pro
    Développeur
    Inscrit en
    Avril 2016
    Messages
    1 470
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur

    Informations forums :
    Inscription : Avril 2016
    Messages : 1 470
    Points : 6 107
    Points
    6 107
    Par défaut
    Petit up, pas pour relancer le débat, mais juste pour partager une anecdote.

    Sur le site open-std.org, je viens de découvrir que, en février 2016, il y a déjà un certain David Wilson qui a proposé un héritage constant : P0277R0 (4 pages) ; P0277R1 (4 pages).

    Par contre, au lieu de proposer que la classe de base constante ne soit pas modifiable dans la classe dérivée, il propose qu'elle soit modifiable, mais uniquement dans les constructeurs de la classe dérivée.
    Ce n'est pas cohérent avec les variables membres constantes :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    struct Foo
    {
        const int i;
        Foo() {i=0;} // ne compile pas
    };

  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 : 49
    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
    Points : 16 213
    Points
    16 213
    Par défaut
    Ce papier a été discuté à Oulu, en l'absence de l'auteur (ce qui n'est jamais bon pour un papier), et a été rejeté à une très large majorité.
    Si j'essaye de résumer les discussions :
    - On ne comprend pas trop à quoi ça servirait
    - Ça pose des conflits avec le reste du langage (par exemple, actuellement, on peut dériver d'un typedef défini comme constant... J'avoue que je ne le savais pas, et je ne sais pas comment ça se comporte, j'imagine que le const est ignoré)
    - L'exemple choisi était particulièrement non motivant
    - Il aurait aussi pu y avoir http://www.open-std.org/jtc1/sc22/wg...014/n4225.html dans la même direction, mais qui avait été rejeté
    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
    Expert éminent
    Avatar de Pyramidev
    Homme Profil pro
    Développeur
    Inscrit en
    Avril 2016
    Messages
    1 470
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur

    Informations forums :
    Inscription : Avril 2016
    Messages : 1 470
    Points : 6 107
    Points
    6 107
    Par défaut
    Citation Envoyé par JolyLoic Voir le message
    Ce papier a été discuté à Oulu, en l'absence de l'auteur (ce qui n'est jamais bon pour un papier), et a été rejeté à une très large majorité.
    Si j'essaye de résumer les discussions :
    Merci pour ces infos. Comment les as-tu eues ?

    Citation Envoyé par JolyLoic Voir le message
    actuellement, on peut dériver d'un typedef défini comme constant... J'avoue que je ne le savais pas, et je ne sais pas comment ça se comporte, j'imagine que le const est ignoré
    Test avec GCC 6.3.0, avec -O2 -Wall -Wextra -pedantic :
    Le const est ignoré :
    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
    struct Base
    {
    	int i;
    	int j;
    	void foo() { j=0; }
    };
     
    typedef const Base ConstBase;
     
    struct Deriv : ConstBase
    {
    	void bar() { i=0; } // pas d'erreur de compilation
    };
     
    int main()
    {
    	Deriv obj;
    	Base& ref = obj; // pas d'erreur de compilation
    	ref.foo();
    	return 0;
    }
    D'ailleurs, dans N4296 (draft de C++14), je n'ai pas réussi à trouver un passage qui évoque les qualificatifs const et volatile pour les classes de base par l'intermédiaire de typedef.

  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 : 49
    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
    Points : 16 213
    Points
    16 213
    Par défaut
    Citation Envoyé par Pyramidev Voir le message
    Merci pour ces infos. Comment les as-tu eues ?
    J'étais dans la salle au moment de la discussion

    Et il y a des prises de notes de ces réunions, mais comme elles sont brut de fonderie, elles sont réservées aux membres du comité. Mais j'ai pu m'en servir pour me rafraichir la mémoire.

    Sinon, j'ai retrouvé dans la norme les aspects liés au const venant d'un typedef :
    Citation Envoyé par Le standard 9.1/5
    A typedef-name (7.1.3) that names a class type, or a cv-qualified version thereof, is also a class-name. If a
    typedef-name that names a cv-qualified class type is used where a class-name is required, the cv-qualifiers
    are ignored. A typedef-name shall not be used as the identifier in a class-head.
    Et au début du chapitre 10, on voit que les classes de base doivent être des class-name.
    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.

Discussions similaires

  1. Héritage de constantes
    Par Troopers dans le forum VB.NET
    Réponses: 4
    Dernier message: 08/03/2009, 18h56
  2. Remerciements, propositions et commentaires
    Par HCath dans le forum Discussions diverses
    Réponses: 57
    Dernier message: 24/08/2006, 10h22
  3. [ADO] Constantes des types de champ
    Par SpaceFrog dans le forum VB 6 et antérieur
    Réponses: 3
    Dernier message: 05/09/2002, 11h08
  4. Héritage entre Forms
    Par BarBal dans le forum Composants VCL
    Réponses: 7
    Dernier message: 29/08/2002, 17h44
  5. Au sujet des constantes
    Par FranT dans le forum Langage
    Réponses: 8
    Dernier message: 09/08/2002, 11h03

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