2015-09-25 1 views
1

Je me demande s'il est possible de rendre une variable de classe inaccessible dans cette classe? Le seul moyen de changer la valeur de cette variable sera le setter de classe. Par exemple:Comment faire une variable de classe inaccessible

class foo 
{ 
private: 
    int m_var; 
    bool m_isBig; 
    void setVar(int a_var) 
    { 
     // do something before setting value, like emitting signal 
     m_var = a_var; 
    } 
    void method() 
    { 
     int copy = m_var; // ok 
     m_var = 5; // error! 
     setVar(101); // ok 
     doSomething(); 
    } 
    void doSomething() 
    { 
     if(m_var > 5) 
     { m_isBig = true; } 
     else 
     { m_isBig = false; } 
    } 
}; 

Je sais que je pourrais écrire une autre classe seulement avec setters et getter, mais je ne veux pas avoir accès à d'autres méthodes/vars de la classe foo (encapsulation!). Je pense que cela pourrait être un problème commun, et il pourrait y avoir un modèle de conception pour cela, mais je ne peux pas en trouver.

EDIT: J'ai édité le code pour être clair, ce que je veux faire dans setter.

+0

duplication possible de [Une variable peut-elle être verrouillée pour empêcher toute modification dans C++?] (Http://stackoverflow.com/questions/13866440/can-a-variable-be-locked-to-prevent-changes- to-it-in-c) –

+0

Vous pourriez probablement obtenir cette fonctionnalité comme vous le dites en créant une autre classe avec seulement des setters et un getter, et ensuite pour donner à cette classe supplémentaire l'accès aux méthodes/vars de foo vous l'auriez déclaré comme un «ami». Je pense que vous pouvez même en faire une classe interne, éventuellement seulement définie dans un fichier d'implémentation si vous voulez vraiment le garder caché. – YoungJohn

+0

pourquoi voulez-vous cela? Si vous avez un membre privé, vous êtes responsable de la mise en œuvre, alors quel est le sens? – Jepessen

Répondre

0

Je ne suis pas au courant d'un modèle pour cela, mais une possibilité est d'envelopper le membre dans une classe imbriquée. Je pense que c'est aussi un meilleur style, puisque la création d'un nouveau type exprime l'intention que ce membre n'est pas seulement un entier, mais qu'il a plutôt un comportement unique.

class foo { 
    class MVar { 
     public: 
     MVar(foo* parent, int value = 0) : m_parent(parent), m_value(value) {} 
     MVar& operator=(const MVar&) = delete; // disable assignment 
     operator int() const { return m_var; } 
     void set(int new_value) { 
      // do something, possibly with m_parent 
      // nested classes have access to the parent's private members 
      m_value = new_value; 
     } 
     private: 
     foo* m_parent; 
     int m_value; 
    } m_var; 
    void method() { 
     int copy = m_var; // ok 
     m_var = 5;  // error 
     MVar.set(101); // ok 
    } 
}; 

Cela ne fait pas tout à fait ce que vous voulez, puisque m_var ne fonctionne pas vraiment ont le même type int, mais il est quelque chose à considérer.

+0

pourquoi le pointeur arrière? pourquoi pas un simple encapsuleur autour d'un int? – TemplateRex

+0

@TemplateRex Si l'action que l'OP souhaite effectuer lors de la définition de la variable doit invoquer des méthodes sur le parent. Le PO dit quelque chose qui pourrait ressembler à cela (mais la question n'est pas entièrement claire). – Brian

+0

cela semble trop compliqué, 'm_var' est un wrapper' int', tout ce qu'il veut, c'est le mettre à une valeur entière. si 'method()' a besoin d'un autre contexte, alors il peut l'obtenir de la classe 'foo', mais sûrement' m_var' n'en a pas besoin – TemplateRex

0

Vous pouvez envelopper l'entier dans une classe spéciale, et seulement définir setVar(), mais pas un opérateur d'affectation prenant un int

class M_type 
{ 
    int m_var; 
public: 
    explicit M_type(int m) : m_var{m} {} 
    operator int() const { return m_var; } 
    void setVar(int a_var) { m_var = a_var; } 
}; 

class foo 
{ 
    M_type m_var; 
    bool m_isBig; 
public: 
    explicit foo(int m) : m_var{m} {}; 

    void method() 
    { 
     int copy = m_var; // OK, calls operator int() 
     m_var = 5; // error, no operator=(int) 
     m_var.setVar(101); // OK, calls setVar(int) 
     doSomething(); 
    } 

    void doSomething() 
    { 
     if(m_var > 5) 
     { m_isBig = true; } 
     else 
     { m_isBig = false; } 
    }  
}; 

Assurez-vous de donner M_type un constructeur explicit prendre un int, et seulement une implicite conversion operator int() qui agit comme un "getter". Si vous rendez également le constructeur implicite, l'affectation générée par le compilateur operator=(M_type const&) sera capable de convertir l'argument 5 en M_type.

0

Vous ne pouvez pas faire exactement ce que vous demandez en C++. Toutes les variables d'une classe sont visibles pour toutes les méthodes d'une classe, qu'elles soient publiques ou privées.

La question que vous voulez vous poser est la suivante: pourquoi une classe voudrait-elle se cacher des choses? L'interface de la classe est la limite entre l'implémentation interne de la classe et les services qu'elle fournit au monde extérieur. Vous êtes à l'intérieur de la classe ou à l'extérieur. Dans cette optique, peut-être que vous utilisez cas est tel que l'écriture d'une classe supplémentaire est la chose appropriée à faire?