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 :

Les préconditions en C++ [Tutoriel]


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Expert confirmé

    Avatar de Francis Walter
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2012
    Messages
    2 315
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Bénin

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

    Informations forums :
    Inscription : Février 2012
    Messages : 2 315
    Par défaut Les préconditions en C++
    Bonjour,

    Je vous présente un tutoriel sur les préconditions en C++ de Andrzej Krzemieński : https://akrzemi1.developpez.com/tuto...remiere-partie
    Il s'agit de la première partie d'une série de quatre épisodes que nous allons faire l'effort de traduire et publier dans les jours à venir. Cette première partie a été traduite par kurtcpp que l'équipe de la rédaction tient à remercier sans oublier les autres contributeurs qui ont aidé à la correction.

    N'hésitez pas à commenter le contenu de ce premier article en répondant à cette discussion.

    P.-S. Si vous désirez contribuer aux traductions de ressources C++, vous pouvez me contacter par MP.



    Les meilleurs cours et tutoriels pour apprendre la programmation C++

  2. #2
    Membre expérimenté Avatar de RPGamer
    Homme Profil pro
    Ingénieur en systèmes embarqués
    Inscrit en
    Mars 2010
    Messages
    168
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : Suisse

    Informations professionnelles :
    Activité : Ingénieur en systèmes embarqués

    Informations forums :
    Inscription : Mars 2010
    Messages : 168
    Par défaut
    Excellente idée que cette traduction. Inspiré par un autre article sur le sujet, j'avais rédigé mes propres macros pour la validation de prédicats par le compilateur dans un simple fichier .hpp et c'est plutot efficace.

    contract.hpp

    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
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    #ifndef __CONTRACT_HPP
    #define __CONTRACT_HPP
     
    #include <Uncopyable.hpp>
    #include <type_traits>
    #include <cassert>
     
    /*!
     * \macro   require
     * \brief   Vérifie la validité d'une précondition.
     */
    #if defined(CONTRACT_NO_PRECONDITION) || defined(CONTRACT_NO_CHECK)
        #define require(contract, text)
    #else
        #define require(contract, text) assert(contract && text)
    #endif
     
    /*!
     * \macro   ensure
     * \brief   Vérifie la validité d'une postcondition.
     */
    #if defined(CONTRACT_NO_POSTCONDITION) || defined(CONTRACT_NO_CHECK)
        #define ensure(contract, text)
    #else
        #define ensure(contract, text) assert(contract && text)
    #endif
     
    /*!
     * \macro   invariant
     * \brief   Vérifie la validité d'un invariant.
     */
    #if defined(CONTRACT_NO_INVARIANT) || defined(CONTRACT_NO_CHECK)
        #define invariant(contract, text)
    #else
        #define invariant(contract, text) assert(contract && text)
    #endif
     
    /*!
     * \macro   invariants
     * \brief   Débute un bloc d'invariants de classe.
     */
    #define invariants(classname) friend class InvariantsChecker<classname>; void _contract_check_invariants() const
     
    /*!
     * \macro   check_invariants
     * \brief   Vérifie la validité des invariants de classe.
     */
    #if defined(CONTRACT_NO_INVARIANT) || defined(CONTRACT_NO_CHECK)
        #define check_invariants()
    #else
        #define check_invariants() _contract_check_invariants()
    #endif
     
    /*!
     * \macro   static_invariants
     * \brief   Débute un bloc d'invariants statiques de classe.
     */
    #define static_invariants(classname) static void _contract_check_static_invariants() const
     
    /*!
     * \macro   check_static_invariants
     * \brief   Vérifie la validité des invariants statiques de classe.
     */
    #if defined(CONTRACT_NO_INVARIANT) || defined(CONTRACT_NO_CHECK)
        #define check_static_invariants()
    #else
        #define check_static_invariants() _contract_check_static_invariants()
    #endif
     
    /*!
     * \class   InvariantsChecker
     * \brief   Vérifie la validité des invariants en début et en fin de scope.
     */
    template <typename T>
    class InvariantsChecker : private Uncopyable
    {
        private:
     
            T *instance;
     
        public:
     
            InvariantsChecker(T *instance) :
                instance(instance)
            {
    #if !defined(CONTRACT_NO_INVARIANT) && !defined(CONTRACT_NO_CHECK)
                instance->_contract_check_invariants();
    #endif
            }
     
            ~InvariantsChecker()
            {
    #if !defined(CONTRACT_NO_INVARIANT) && !defined(CONTRACT_NO_CHECK)
                instance->_contract_check_invariants();
    #endif
            }
    };
     
    #endif // __CONTRACT_HPP
    On peut alors facilement l'utiliser :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    int divide(int dividend, int divisor)
    {
        require(divisor != 0, "Division par zéro indéfinie.");
        return dividend / divisor;
    }
    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
    class Square
    {
        private:
     
            size_t width;
            size_t height;
     
            invariants(Square)
            {
                invariant(width == height, "Un carré a 4 côtés égaux.");
            }
     
        public:
     
            Square(size_t width, size_t height) : 
                width(width), height(height)
            {
                check_invariants();
            }
            void resize(size_t width, size_t height)
            {
                InvariantsChecker<Square> check(this);
                this->width = width;
                this->height = height;
            }
            size_t getWidth() const
            {
                InvariantsChecker<Square> check(this);
                return width;
            }
            size_t getHeight() const
            {
                InvariantsChecker<Square> check(this);
                return height;
            }
    };

  3. #3
    Expert confirmé

    Avatar de Francis Walter
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2012
    Messages
    2 315
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Bénin

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

    Informations forums :
    Inscription : Février 2012
    Messages : 2 315
    Par défaut Préconditions en C++ - Partie 2
    Bonjour,

    Je vous annonce la deuxième partie de la série de tutoriels sur les préconditions en C++ écrits par Andrzej Krzemieński. Elle a été traduite par kurtcpp.

    Lire le tutoriel : Préconditions en C++ - Partie 2

    Citation Envoyé par Auteur
    Dans ce billet, je continuerai à partager mes réflexions sur les préconditions. Il traitera un peu de la philosophie qui est derrière le concept des préconditions (et des bugs), et étudiera la possibilité de mettre à profit le compilateur pour vérifier certaines préconditions. Plusieurs lecteurs ont fourni des retours utiles dans mon précédent billet, j'essaierai de les incorporer à celui-ci.
    Autres ressources du même auteur : Blog de Andrzej Krzemieński.

  4. #4
    Membre expérimenté Avatar de RPGamer
    Homme Profil pro
    Ingénieur en systèmes embarqués
    Inscrit en
    Mars 2010
    Messages
    168
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : Suisse

    Informations professionnelles :
    Activité : Ingénieur en systèmes embarqués

    Informations forums :
    Inscription : Mars 2010
    Messages : 168
    Par défaut
    En réutilisant les macros précédentes, faciles à mettre en oeuvre, on peut réaliser des "classes contractuelles" permettant d'imposer un contrat-type à une série de classes filles mais aussi de gérer les cas problématiques d'appels récursifs ou de retours multiples. Exemple :

    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
    class ContractualClass
    {
        private:
     
            virtual int doFunc(int n) // cette fonction est un exemple de retour multiple sans contrat
            {
                if (n > 0)
                {
                    return 1/n;
                }
                else
                {
                    return 2/n;
                }
            }
     
        public:
     
            int func(int n)
            {
                require(n != 0, "n différent de 0.");
                int ret = doFunc(n);
                ensure(ret >= -2 && ret <= 1, "Valeur de retour dans l'intervalle [-2, 1].");
                return ret;
            }
    };
     
    class InheritedContractClass : public ContractualClass
    {
        private:
     
            virtual int doFunc(int n)
            {
                return 10*n; // violation du contrat de la classe mère !
            }
    };
    On peut même imaginer redéfinir un nouveau contrat qui entre dans le domaine du contrat hérité :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    class InheritedContractClass : public ContractualClass
    {
        public:
     
            int func(int n)
            {
                int ret = ContractualClass::func(n);
                ensure(ret >= -2 && ret <= 0, "Valeur de retour dans l'intervalle [-2, 0].");
                return ret;
            }
    };
    Ici la valeur de retour ne doit plus être comprise dans l'interval [-2, 1] mais dans un nouvel intervalle [-2, 0].

  5. #5
    Expert confirmé
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 287
    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 287
    Par défaut
    Cela s'appelle le pattern NVI, pour Non-Virtual-Interface.
    Par contre, cela se corse en cas d'héritage de multiple "interface/contrats" pour traiter les invariants.

    -> http://luchermitte.github.io/blog/20...e-c-plus-plus/
    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...

  6. #6
    Membre expérimenté Avatar de RPGamer
    Homme Profil pro
    Ingénieur en systèmes embarqués
    Inscrit en
    Mars 2010
    Messages
    168
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : Suisse

    Informations professionnelles :
    Activité : Ingénieur en systèmes embarqués

    Informations forums :
    Inscription : Mars 2010
    Messages : 168
    Par défaut
    Citation Envoyé par Luc Hermitte Voir le message
    Par contre, cela se corse en cas d'héritage de multiple "interface/contrats" pour traiter les invariants.
    Avec l'approche que je donne, chaque implémentation (doFunc()) possède une fonction d'appel public (func()) vérifiant les invariants. Il n'y a donc aucune confusion sur le contrat. En revanche, un développeur imprudent pourrait alléger le contrat en redéfinissant la fonction d'appel public de façon erronée mais ça entre aussi dans le cadre du changement de portée permis par l'héritage C++ par exemple. En principe on ne le fait pas, à moins d'avoir une très bonne raison.

Discussions similaires

  1. Les meilleurs cours et tutoriels C++
    Par Community Management dans le forum C++
    Réponses: 1
    Dernier message: 13/05/2015, 13h50
  2. Obligatoire : lisez les règles du forum : MAJ 06/08/2010
    Par Anomaly dans le forum Mode d'emploi & aide aux nouveaux
    Réponses: 0
    Dernier message: 03/07/2008, 13h46
  3. Réponses: 5
    Dernier message: 20/08/2002, 18h01
  4. recherches des cours ou des explications sur les algorithmes
    Par Marcus2211 dans le forum Algorithmes et structures de données
    Réponses: 6
    Dernier message: 19/05/2002, 22h18
  5. Une petite aide pour les API ?
    Par Yop dans le forum Windows
    Réponses: 2
    Dernier message: 04/04/2002, 21h45

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