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 :

Réduire la visibilité d'une fonction membre


Sujet :

Langage C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2009
    Messages
    4 493
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Loire Atlantique (Pays de la Loire)

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

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 493
    Billets dans le blog
    1
    Par défaut Réduire la visibilité d'une fonction membre
    Bonjour,

    Voici un code me permettant de réduire la visibilité d'une fonction membre :

    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
    #include <iostream>
     
    class Base
    {
    public:
        virtual void f()
        {
            std::cout << "Base::f()" << std::endl;
        }
    };
     
    class Derived : public Base
    {
    private:
       // Visibilité réduite
        void f() override
        {
            Base::f();
        }
    };
     
    int main(void)
    {
        Derived d;
     
        d.f();
    }
    Y a t-il un moyen plus élégant de faire ceci ?

    Merci d'avance !

  2. #2
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2009
    Messages
    4 493
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Loire Atlantique (Pays de la Loire)

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

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 493
    Billets dans le blog
    1
    Par défaut
    En cherchant comment faire l'inverse (rendre public quelque chose de privé), je suis tombé sur la solution à mon problème orignal. Voici la solution plus élégante :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    class Derived : public Base
    {
    private:
        using Base::f;
    };

    Dans le même temps, je me demande vraiment s'il y a un intérêt à faire ça... mais c'est un autre sujet

  3. #3
    Expert confirmé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 502
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2005
    Messages : 5 502
    Par défaut
    Pour moi, c'est un refus d'héritage, donc une erreur de conception.
    Le concepteur devrait être en droit de maitriser les appel à "f" et c'est pas le cas :
    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
    #include <iostream>
     
    class Base
    {
    public:
        virtual void f()
        {
            std::cout << "Base::f()" << std::endl;
        }
    };
     
    class Derived : public Base
    {
    private:
        using Base::f;
    };
     
    int main(void)
    {
        Base d = Derived();
     
        d.f();
    }

  4. #4
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 152
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 152
    Billets dans le blog
    4
    Par défaut
    L'intérêt me semble moindre puisque ta nouvelle portée n'est utilisée que dans le cas où Derived est typée statiquement. Si tu utilises le polymorphisme et travailles sur des Base*, ce qui est normalement le plus souvent le cas dans une relation d'héritage, c'est toujours public.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  5. #5
    Expert confirmé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 502
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2005
    Messages : 5 502
    Par défaut
    C'est bien là le problème.
    Le mainteneur de la classe "Derived" fait l'assertion qu'il est le seul à pouvoir utiliser cette méthode, même pas les classes dérivée de "Derived".
    Il pourrait donc la modifier s'en avoir à concevoir tout l'attirail qu'entraine des méthodes publiques (vérification des arguments, les pré-conditions, les post-conditions, etc...).

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

    Informations professionnelles :
    Activité : Tech Lead

    Informations forums :
    Inscription : Avril 2016
    Messages : 1 513
    Par défaut
    Bonjour,

    Citation Envoyé par Bktero Voir le message
    Voici un code me permettant de réduire la visibilité d'une fonction membre :

    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
    #include <iostream>
     
    class Base
    {
    public:
        virtual void f()
        {
            std::cout << "Base::f()" << std::endl;
        }
    };
     
    class Derived : public Base
    {
    private:
       // Visibilité réduite
        void f() override
        {
            Base::f();
        }
    };
     
    int main(void)
    {
        Derived d;
     
        d.f();
    }
    Ce code ne réduit pas la visibilité de Base::f. En effet, si tu remplaces d.f(); par d.Base::f();, tu constateras que cela compile.
    Si Derived dérive publiquement de Base, alors ça veut dire que tu veux que Base soit publique, donc que ses fonctions publiques soient accessibles pour l'utilisateur.
    Si tu veux de l'héritage, mais que Base soit privée, alors il faut faire de l'héritage privé.

    Voici un exemple concret qui utilise l'héritage privé :
    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
    #include <cassert>
    #include <iosfwd>
    #include <stdexcept>
     
    ////////////////////////////////////////////////
    // External code which the user cannot modify //
    ////////////////////////////////////////////////
     
    class WorkerConstVisitor;
     
    class Worker {
    public:
    	virtual void accept(WorkerConstVisitor& visitor) const = 0;
    	// ...
    };
     
    class Consultant;
    class Trainee;
     
    class WorkerConstVisitor {
    public:
    	virtual void visit(const Consultant& visited) = 0;
    	virtual void visit(const Trainee&    visited) = 0;
    	// ...
    };
     
    class Consultant final : public Worker {
    public:
    	void accept(WorkerConstVisitor& visitor) const final {visitor.visit(*this);}
    	// ...
    };
     
    class Trainee final : public Worker {
    public:
    	void accept(WorkerConstVisitor& visitor) const final {visitor.visit(*this);}
    	// ...
    };
     
    ///////////////
    // User code //
    ///////////////
     
    class Config final {
    	// ...
    };
     
    class PrintWorkerDescriptionImpl final : private WorkerConstVisitor {
    public:
    	PrintWorkerDescriptionImpl(std::ostream& os, const Worker& worker, const Config& config) :
    		m_os{os}, m_config{config}, m_printDone{false}
    	{
    		worker.accept(*this);
    		assert(m_printDone);
    		if(!m_printDone)
    			throw std::logic_error("The visit function did not do the work.");
    				// It can happen if a NON PURE virtual function "visit" is added to
    				// WorkerConstVisitor, but such an addition would be a development mistake.
    	}
    private:
    	void visit(const Consultant& visited) final
    	{
    		// ...
    		m_printDone = true;
    	}
    	void visit(const Trainee& visited) final
    	{
    		// ...
    		m_printDone = true;
    	}
    	std::ostream& m_os;
    	const Config& m_config;
    	bool          m_printDone;
    };
     
    void printWorkerDescription(std::ostream& os, const Worker& worker, const Config& config)
    {
    	PrintWorkerDescriptionImpl{os, worker, config};
    }
    Edit 2017-08-24-22h45 : Renommage de printDescription en printWorkerDescription.

  7. #7
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2009
    Messages
    4 493
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Loire Atlantique (Pays de la Loire)

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

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 493
    Billets dans le blog
    1
    Par défaut
    Je vais décrire la situation plus globalement

    Je développe une interface graphique pour l'embarqué. Le framework m'offre les classes suivantes:
    - Drawable qui est abstraite (avec quelques méthodes virtuelles pures)
    - Container qui est n'est pas abstraite et qui hérite publiquement de Drawable. C'est une sorte de composite / layout. Elle ajoute notamment une méthode add(Drawable)

    Je crée des layouts personnalisés, donc des classes héritant de Container. J'ai notamment ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    class Layout_1 : public Container
    {
    public:
        void setTitle(Drawable& top);
    }
    Comme Layout_1 dérive de Container, je peux faire ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    Label label("title");
    Layout_1 layout;
    layout.add(label);
    Sauf que add() ne faire rien visuellement, c'est un peu un méthode interne... Je me demande d'ailleurs pourquoi Container n'est pas abstraite et add() protected mais passons... J'aurais aimé la masquer pour que l'API de mon Layout_1 soit simple à utiliser correctement et difficile à utiliser incorrectement (http://programmer.97things.oreilly.c...se_Incorrectly). Cette histoire de réduire la visibilité n'est pas une bonne solution.

    Mon idée suivante a donc été celle-ci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    class Layout_1 : private Container,  public Drawable
    {
    };
    Sauf que bien sûr je me retrouve avec des tas d'erreurs :
    "C:\Program Files\JetBrains\CLion 2017.2\bin\cmake\bin\cmake.exe" --build C:\Users\X-pigradot\svn\0373_AI_Island_Delight_trunk\cmake-build-debug --target aivg-delight-simulation -- -j 2
    Scanning dependencies of target aivg-delight-simulation
    [  1%] Building CXX object CMakeFiles/aivg-delight-simulation.dir/simulator/source/main.cpp.obj
    In file included from C:\Users\X-pigradot\svn\0373_AI_Island_Delight_trunk\simulator\source\main.cpp:10:0:
    C:/Users/X-pigradot/svn/0373_AI_Island_Delight_trunk/Software/application/Common/delight/page/TestPage.hpp:60:7: warning: direct base 'touchgfx::Drawable' inaccessible in 'Layout_1' due to ambiguity
     class Layout_1 : private Container,  public Drawable
           ^
    C:/Users/X-pigradot/svn/0373_AI_Island_Delight_trunk/Software/application/Common/delight/page/TestPage.hpp:144:14: error: cannot declare field 'TestPage::layout_m' to be of abstract type 'Layout_1'
         Layout_1 layout_m;
                  ^
    C:/Users/X-pigradot/svn/0373_AI_Island_Delight_trunk/Software/application/Common/delight/page/TestPage.hpp:60:7: note:   because the following virtual functions are pure within 'Layout_1':
     class Layout_1 : private Container,  public Drawable
           ^
    In file included from C:/Users/X-pigradot/svn/0373_AI_Island_Delight_trunk/Software/touchgfx/framework/include/touchgfx/containers/Container.hpp:42:0,
                     from C:/Users/X-pigradot/svn/0373_AI_Island_Delight_trunk/Software/touchgfx/framework/include/touchgfx/Screen.hpp:46,
                     from C:/Users/X-pigradot/svn/0373_AI_Island_Delight_trunk/Software/application/Common/delight/page/Page.hpp:4,
                     from C:/Users/X-pigradot/svn/0373_AI_Island_Delight_trunk/Software/application/Common/delight/page/TestPage.hpp:4,
                     from C:\Users\X-pigradot\svn\0373_AI_Island_Delight_trunk\simulator\source\main.cpp:10:
    C:/Users/X-pigradot/svn/0373_AI_Island_Delight_trunk/Software/touchgfx/framework/include/touchgfx/Drawable.hpp:113:18: note: 	virtual void touchgfx::Drawable::draw(const touchgfx::Rect&) const
         virtual void draw(const Rect& invalidatedArea) const = 0;
                      ^
    C:/Users/X-pigradot/svn/0373_AI_Island_Delight_trunk/Software/touchgfx/framework/include/touchgfx/Drawable.hpp:129:18: note: 	virtual touchgfx::Rect touchgfx::Drawable::getSolidRect() const
         virtual Rect getSolidRect() const = 0;
                      ^
    C:/Users/X-pigradot/svn/0373_AI_Island_Delight_trunk/Software/touchgfx/framework/include/touchgfx/Drawable.hpp:202:18: note: 	virtual void touchgfx::Drawable::getLastChild(int16_t, int16_t, touchgfx::Drawable**)
         virtual void getLastChild(int16_t x, int16_t y, Drawable** last) = 0;
                      ^
    In file included from C:\Users\X-pigradot\svn\0373_AI_Island_Delight_trunk\simulator\source\main.cpp:10:0:
    C:/Users/X-pigradot/svn/0373_AI_Island_Delight_trunk/Software/application/Common/delight/page/TestPage.hpp: In member function 'virtual void TestPage::setupScreen()':
    C:/Users/X-pigradot/svn/0373_AI_Island_Delight_trunk/Software/application/Common/delight/page/TestPage.hpp:126:44: error: 'touchgfx::Drawable' is an ambiguous base of 'Layout_1'
             layout_m.setPosition(0, 0, 320, 240);
                                                ^
    C:/Users/X-pigradot/svn/0373_AI_Island_Delight_trunk/Software/application/Common/delight/page/TestPage.hpp:126: confused by earlier errors, bailing out
    
    J'ai essayé de rajouter ceci dans ma classe, mais ça n'a pas eu l'effet désiré...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    public:
        using Container::draw;
        using Container::getSolidRect;
        using Container::setPosition;
        using Container::getLastChild;

  8. #8
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 152
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 152
    Billets dans le blog
    4
    Par défaut
    Le problème de class Layout_1 : private Container, public Drawable c'est que tu te retrouves avec un héritage en diamant, et c'est assez rarement une bonne chose.
    Pourquoi vouloir hériter de Container et ne pas simplement en faire une composition ?
    As-tu besoin à quelconque moment de traiter tes Layout_1 comme Container ou Drawable ?
    Si oui, de toute façon c'est la visibilité de la classe mère qui l'emporte si tu manipules un Base* (Drawable*), donc ce que tu as fait ne changes rien du tout.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  9. #9
    Expert éminent

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 202
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 202
    Par défaut
    J'aurai vu le "layout" comme une sorte de "LayoutManager" de Swing (en Java), c'est à dire une stratégie/politique à chaud.
    Tu aurais un "LayoutableContainer", qui hérite de Container, et applique le layout au add (et au resize)

  10. #10
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2009
    Messages
    4 493
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Loire Atlantique (Pays de la Loire)

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

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 493
    Billets dans le blog
    1
    Par défaut
    Mais oui ! Préférer la composition à l'héritage !

    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
    class Layout : public Drawable
    {
    public:
        void draw(const Rect& rect) const override
        {
            container_m.draw(rect);
        }
     
        // Idem pour les autres fonctions membres abstraites
     
    protected:
        Container container_m;
     
        void add(Drawable& drawable)
        {
            container_m.add(drawable);
        }
     
        void remove(Drawable& drawable)
        {
            container_m.remove(drawable);
        }
    };
     
    class Layout_1 : public Layout
    {
        ...
    };
    Du coup, Layout_1 n'expose plus publiquement ce add() piégeux mais uniquement des fonctions intéressantes. Il reste disponible dans Layout_1 qui en a besoin pour ajouter ses composants à la hiérarchie des drawables. Je crois que c'est la bonne solution à mon problème

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 14
    Dernier message: 16/05/2006, 11h26
  2. Réponses: 3
    Dernier message: 29/04/2006, 13h02
  3. Réponses: 4
    Dernier message: 01/12/2005, 12h33
  4. Réponses: 3
    Dernier message: 28/11/2005, 12h15
  5. Thread avec une fonction membre d'une classe
    Par SteelBox dans le forum Windows
    Réponses: 6
    Dernier message: 01/03/2004, 01h15

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