Переменные класса: открытый доступ только для чтения, но частный доступ для чтения / записи - PullRequest
46 голосов
/ 24 марта 2011

Вау, на данный момент не работает с этой библиотекой сокетов. Я пытаюсь научиться немного больше в C ++.

С классами, есть ли способ сделать переменную доступной только для чтения для публики, но для чтения и записи при частном доступе? например как то так:

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;
}

Мой вопрос, в сжатой форме, как разрешить полный доступ к x из f(), но доступ только для чтения из любого другого места, то есть int newint = temp.x; разрешен, но temp.x = 5; не разрешен? как переменная const, но доступная для записи из f() ...

РЕДАКТИРОВАТЬ: я забыл упомянуть, что я планирую возвращать большой экземпляр вектора, использование функции getX () только сделает копию этого, и это не совсем оптимально. Я мог бы вернуть указатель на него, но это плохая практика iirc.

P.S .: Куда я отправлю сообщение, если я просто хочу показать свои знания указателей и спросить, завершено ли это или нет? Спасибо!

Ответы [ 12 ]

47 голосов
/ 24 марта 2011

Хотя я думаю, что функция получения, которая возвращает const T&, является лучшим решением, вы можете почти точно иметь синтаксис, который вы запрашивали:

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

}

РЕДАКТИРОВАНИЕ : с проксикласс, вы можете получить именно тот синтаксис, который вы запрашивали:

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 в классе выглядит как чтение-запись int, но только для чтения int в main.

43 голосов
/ 24 марта 2011

Конечно вы можете:

class MyClass
{
    int x_;

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

Если вы не хотите делать копию (для целых чисел нет накладных расходов), сделайте следующее:

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

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

Это не делает никаких копий.Возвращает ссылку на const .

10 голосов
/ 01 сентября 2017

Простое решение, как у Роба, но без конструктора:

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

}

Походит на метод get, но короче. Интересующий вопрос ... что-то вроде. член const bool; может сэкономить много получателей ... но я не знаю языков с этой функцией ...

5 голосов
/ 01 апреля 2014

Это может делать то, что вы хотите.

Если вы хотите переменную только для чтения, но не хотите, чтобы клиент должен был изменить способ доступа к ней, попробуйте этот шаблонный класс:

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;                                                                                
};      

Пример использования:

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

Теперь вы можете получить доступ к Foo.x, но не можете изменить Foo.x!Помните, что вам нужно добавить побитовые и унарные операторы!Это всего лишь пример, с которого можно начать

2 голосов
/ 11 октября 2016

Есть способ сделать это с помощью переменной-члена, но это, вероятно, не рекомендуемый способ сделать это.

Иметь закрытый доступный для записи член и общедоступную переменную-член, ссылающуюся на член класса своего собственного класса.

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 )
  {
  }
};

Это даст вам то, что вы хотите.

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

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

Что вы можете сделать, и что вы должны сделать, это разные вопросы. Я не уверен, что метод, который я только что изложил, популярен и прошел бы много обзоров кода. Это также излишне увеличивает sizeof (Foo) (хотя и на небольшое количество), тогда как простой метод доступа «getter» не будет и может быть встроенным, так что он также не будет генерировать больше кода.

1 голос
/ 24 марта 2011

Возможно, вы захотите имитировать свойства C # для доступа (в зависимости от того, к чему вы стремитесь, предполагаемой среды и т. Д.).

class Foo
{
  private:
    int bar;

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

    void Getter() const
    {
      return bar;
    }
}
1 голос
/ 24 марта 2011

Вы должны оставить его закрытым, а затем создать функцию для доступа к значению;

private:

    int x;

public:

    int X()
    {
        return x;
    }
1 голос
/ 24 марта 2011

Единственный способ, которым я знаю о предоставлении доступа только для чтения частным элементам данных в классе c ++, - это иметь открытую функцию.В вашем случае он будет выглядеть так:

int getx() const { return x; }

или

int x() const { return x; }.

Делая элемент данных закрытым, вы по умолчаниюделая его невидимым (он же не имеет доступа) к области видимости за пределами класса.По сути, члены класса имеют доступ на чтение / запись к частному члену данных (при условии, что вы не указываете его как const).friend класса получают доступ к закрытым членам данных.

См. здесь и / или любую хорошую книгу C ++ по спецификаторам доступа.

1 голос
/ 24 марта 2011

Вам нужно сделать член private и предоставить public метод получения.

0 голосов
/ 21 апреля 2019

Как уже упоминалось в других ответах, вы можете создать функцию только для чтения для члена класса, сделав его закрытым и определив функцию получения, но не установщик. Но это большая работа для каждого ученика.

Вы также можете использовать макросы для автоматического создания функций получения:

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

Тогда вы можете сделать класс таким образом:

class myClass {
    readonly(int, x)
}

, который расширяется до

class myClass {
    private: int x;
    public: int get_x() {
        return x;
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...