web-dev-qa-db-fra.com

Variables de classe: accès public en lecture seule, mais accès privé en lecture / écriture

Whoopee, ne travaillant pas sur cette bibliothèque de sockets pour le moment. J'essaie de m'éduquer un peu plus en C++.

Avec les classes, existe-t-il un moyen de rendre une variable accessible en lecture seule au public, mais de lire et d'écrire en cas d'accès privé? par exemple. quelque chose comme ça:

class myClass {
    private:
    int x; // this could be any type, hypothetically

    public:
    void f() {
        x = 10; // this is OK
    }
}

int main() {
    myClass temp;

    // I want this, but with private: it's not allowed
    cout << temp.x << endl;


    // this is what I want:

    // this to be allowed
    temp.f(); // this sets x...

    // this to be allowed
    int myint = temp.x;

    // this NOT to be allowed
    temp.x = myint;
}

Ma question, condensée, est de savoir comment autoriser un accès complet à x depuis f() mais un accès en lecture seule depuis n'importe où ailleurs, c'est-à-dire int newint = temp.x; Autorisé, mais temp.x = 5; interdit? comme une variable const, mais accessible en écriture depuis f()...

EDIT: J'ai oublié de mentionner que je prévois de retourner une grande instance vectorielle, en utilisant une fonction getX () n'en ferait qu'une copie et ce n'est pas vraiment optimal. Je pourrais y retourner un pointeur, mais c'est une mauvaise pratique iirc.

P.S .: Où publierais-je si je veux simplement montrer ma connaissance des pointeurs et demander si c'est complet ou non? Merci!

47
FurryHead

Bien sûr vous pouvez:

class MyClass
{
    int x_;

public:
    int x() const { return x_; }
};

Si vous ne voulez pas faire de copie (pour les entiers, il n'y a pas de surcharge), procédez comme suit:

class MyClass
{
    std::vector<double> x_;

public:
    const std::vector<double>& x() const { return x_; }
};

Cela ne fait aucune copie. Il renvoie un référence à const.

44
Alexandre C.

Bien que je pense qu'une fonction getter qui renvoie const T& est la meilleure solution, vous pouvez avoir presque exactement la syntaxe que vous avez demandée:

class myClass {
    private:
    int x_; // Note: different name than public, read-only interface

    public:
    void f() {
        x_ = 10; // Note use of private var
    }
    const int& x;
    myClass() : x_(42), x(x_) {} // must have constructor to initialize reference
};

int main() {
    myClass temp;

    // temp.x is const, so ...
    cout << temp.x << endl; // works
    // temp.x = 57;  // fails

}

EDIT : Avec une classe proxy, vous pouvez obtenir précisément la syntaxe que vous avez demandée:

class myClass {
public:

    template <class T>
    class proxy {
        friend class myClass;
    private:
        T data;
        T operator=(const T& arg) { data = arg; return data; }
    public:
        operator const T&() const { return data; }
    };

    proxy<int> x;
    // proxy<std::vector<double> > y;


    public:
    void f() {
        x = 10; // Note use of private var
    }
};

temp.x semble être une lecture-écriture int dans la classe, mais une lecture seule int dans main.

47
Robᵩ

Une solution simple, comme Rob, mais sans constructeur:

class myClass {
    private:
    int m_x=10; // Note: different name than public, read-only interface
    public:
    const int& x=m_x;

};

int main() {
    myClass temp;

    // temp.x is const, so ...
    cout << temp.x << endl; // works
    // temp.x = 57;  // fails

}

C'est comme une méthode get, mais plus courte. Question intéressante ... quelque chose comme. mesure const bool membre; peut sauver beaucoup de getters ... mais je ne connais pas les langues avec cette fonctionnalité ...

10
Miguel Angel Pons

Cela peut faire ce que vous voulez.

Si vous voulez une variable en lecture seule mais ne voulez pas que le client doive changer la façon dont il y accède, essayez cette classe basée sur un modèle:

template<typename MemberOfWhichClass, typename primative>                                       
class ReadOnly {
    friend MemberOfWhichClass;
public:
    inline operator primative() const                 { return x; }

    template<typename number> inline bool   operator==(const number& y) const { return x == y; } 
    template<typename number> inline number operator+ (const number& y) const { return x + y; } 
    template<typename number> inline number operator- (const number& y) const { return x - y; } 
    template<typename number> inline number operator* (const number& y) const { return x * y; }  
    template<typename number> inline number operator/ (const number& y) const { return x / y; } 
    template<typename number> inline number operator<<(const number& y) const { return x <<y; }
    template<typename number> inline number operator>>(const number& y) const { return x >> y; }
    template<typename number> inline number operator^ (const number& y) const { return x ^ y; }
    template<typename number> inline number operator| (const number& y) const { return x | y; }
    template<typename number> inline number operator& (const number& y) const { return x & y; }
    template<typename number> inline number operator&&(const number& y) const { return x &&y; }
    template<typename number> inline number operator||(const number& y) const { return x ||y; }
    template<typename number> inline number operator~() const                 { return ~x; }

protected:
    template<typename number> inline number operator= (const number& y) { return x = y; }       
    template<typename number> inline number operator+=(const number& y) { return x += y; }      
    template<typename number> inline number operator-=(const number& y) { return x -= y; }      
    template<typename number> inline number operator*=(const number& y) { return x *= y; }      
    template<typename number> inline number operator/=(const number& y) { return x /= y; }      
    template<typename number> inline number operator&=(const number& y) { return x &= y; }
    template<typename number> inline number operator|=(const number& y) { return x |= y; }
    primative x;                                                                                
};      

Exemple d'utilisation:

class Foo {
public:
    ReadOnly<Foo, int> x;
};

Vous pouvez maintenant accéder à Foo.x, mais vous ne pouvez pas changer Foo.x! N'oubliez pas que vous devrez également ajouter des opérateurs au niveau du bit et unaires! Ce n'est qu'un exemple pour vous aider à démarrer

5
Jonathan

Il existe un moyen de le faire avec une variable membre, mais ce n'est probablement pas le moyen conseillé de le faire.

Avoir un membre privé accessible en écriture et une variable de membre public de référence const qui alias un membre de sa propre classe.

class Foo
{
  private:
      Bar private_bar;

  public:
      const Bar& readonly_bar; // must appear after private_bar
                              // in the class definition

  Foo() :
       readonly_bar( private_bar )
  {
  }
};

Cela vous donnera ce que vous voulez.

void Foo::someNonConstmethod()
{
    private_bar.modifyTo( value );
}

void freeMethod()
{
    readonly_bar.getSomeAttribute();
}

Ce que vous pouvez faire et ce que vous devez faire sont différents. Je ne suis pas sûr que la méthode que je viens de décrire est populaire et passerait de nombreux examens de code. Il augmente également inutilement sizeof (Foo) (quoique légèrement) alors qu'un simple accesseur "getter" ne le ferait pas, et peut être intégré, donc il ne générera pas plus de code non plus.

2
CashCow

Vous devez le laisser privé, puis créer une fonction pour accéder à la valeur;

private:

    int x;

public:

    int X()
    {
        return x;
    }
1
NeilPearson

Vous voudrez peut-être imiter C # propriétés pour l'accès (en fonction de ce que vous recherchez, de l'environnement prévu, etc.).

class Foo
{
  private:
    int bar;

  public:
    __declspec( property( get = Getter ) ) int Bar;

    void Getter() const
    {
      return bar;
    }
}
1
Brad Christie

Vous devez créer le membre private et fournir une méthode getter public.

1
Jon

La seule façon que je connaisse d'accorder un accès en lecture seule aux membres de données privées dans une classe c ++ est d'avoir une fonction publique. Dans votre cas, il aimera:

int getx() const { return x; }

ou

int x() const { return x; }.

En rendant un membre de données privé, vous le rendez par défaut invisible (c'est-à-dire sans accès) à la portée en dehors de la classe. En substance, les membres de la classe ont un accès en lecture/écriture au membre de données privées (en supposant que vous ne spécifiez pas qu'il s'agit de const). friends de la classe ont accès aux membres des données privées.

Reportez-vous ici et/ou n'importe quel bon livre C++ sur les spécificateurs d'accès.

1
yasouser

Comme mentionné dans d'autres réponses, vous pouvez créer une fonctionnalité en lecture seule pour un membre de la classe en la rendant privée et en définissant une fonction getter mais pas de setter. Mais c'est beaucoup de travail à faire pour chaque membre de la classe.

Vous pouvez également utiliser des macros pour générer automatiquement des fonctions getter:

#define get_trick(...) get_
#define readonly(type, name) \
private: type name; \
public: type get_trick()name() {\
    return name;\
}

Ensuite, vous pouvez faire le cours de cette façon:

class myClass {
    readonly(int, x)
}

qui s'étend à

class myClass {
    private: int x;
    public: int get_x() {
        return x;
    }
}
0
Dinkydau Set

Écrivez une fonction getter publique.

int getX(){ return x; }
0
hfitzwater