Можно ли заблокировать переменную, чтобы предотвратить ее изменения в C++?

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

код, чтобы объяснить:

class myClass {
    int x;  // This should be prevented to being changed most of the time
    int y;  // Regular variable
    myclass() {x = 1;}
    void foo1 () {x++; y++;} // This can change x
    void foo2 () {x--; y--;} // This shouldn't be able to change x
                             // I want it to throw a compile error
};

вопрос в том, может ли это быть достигнуто каким-то образом? Что-то вроде постоянного const_cast?

Я знаю, что могу сразу использовать список инициализации конструктора и константу, но мне нужно изменить переменную позже.

7 ответов


хорошо, все остальные ответы мне не нравятся, поэтому вот моя идея: скрыть переменную.

#define READONLY(TYPE, VAR) const TYPE& VAR = this->VAR //C++03
#define READONLY(VARIABLE) const auto& VARIABLE = this->VARIABLE //C++11

class myClass {
    int x;  // This should be prevented to being changed most of the time
    int y;  // Regular variable
    myClass() :x(1), y(2) {}
    void foo1 () {// This can change x
        x++; 
        y++;
    } 
    void foo2 () {// This shouldn't be able to change x
        READONLY(x); //in this function, x is read-only
        x++; //error: increment of read-only variable 'x'
        y++;
    } 
};

есть еще способы обойти блокировку переменной (например,this->x), но ничего нельзя сделать для этих ситуаций.


class myClass {
    int x;
    mutable int y;
public:
    myclass() : x(1) {}
    void foo1 () {x++; y++}      // this can change x or y
    void foo2 () const { y--; }  // this can't change x by can change y
};

если вы отмечаете функцию-член const как это, вы не можете сделать ничего в этом члене, который изменил бы член объекта (если этот член не mutable или static - и static не является членом объекта вообще).

обратите внимание, что это не просто помешает вам вызвать функцию, которая пытается сделать такую модификацию - скорее, функцию, которая отмечена const но попытка изменить состояние объекта не будет компилироваться вообще.

I следует добавить, однако, что я вовсе не уверен, что это действительно лучший дизайн. Скорее наоборот, это звучит для меня как ваши требования на x и y достаточно сложны, что они, вероятно, будут иметь больше смысла как отдельные классы, которые непосредственно применяют правильные ограничения (например, предоставляя перегрузку для operator=, который принимает ввод только при правильных обстоятельствах).

другими словами, использование mutable Я показал выше (я так думаю) самый простой и прямой ответ на заданный вами вопрос:--17-->но кажется довольно вероятным, что вы на самом деле не задаете вопрос, который должны, и вы, скорее всего, выиграете от изменения дизайна-к сожалению, вы недостаточно рассказали нам о "большой картине", чтобы предложить, какой лучший дизайн может быть.


Ну, я не уверен, что это стоит ваших усилий, в любом случае, на случай, если это викторина или sth, попробуйте объединить частное наследование с другом:

class MyClassX {
protected:
  MyClassX() : x(1) {}
  int x;
public:
  int getX() const { return x; } // read only access
};
class MyClassY {
protected:
  MyClassY() : y(0) {}
  int y;
  friend class MyClass;
public:
  int getY() const { return y; }
};
class MyClassXY : private MyClassX, private MyClassY {
public:
    void foo1 () {x++; y++}      // this can change x or y
};
MyClass : public MyClassXY {
public:
    void foo2 () const { y--; }  // this can't change x but can change y
};

сделать x a private член subClass, и сделать foo1 функция друг subClass. Вот так:

class myClass {
    int y;  // Regular variable
    myClass() : x (1) {}
    void foo1 () {x.x++; y++;} // This can change x
    void foo2 () {x.x--; y--;} // This shouldn't be able to change x
                            // I want it to throw a compile error
    class subClass {
      friend void myClass::foo1() ; // This must come after the declaration of foo1
      int x ; // private
    public:
      subClass (int x) : x (x) { }
      int read_x() const { return x ; }
      } x ;
};

это вызывает ошибку компилятора, именно там, где вы этого хотели.


Ну вы не можете делать то, что пытаются сделать... Кто-нибудь поправьте меня, если я ошибаюсь.


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


создайте класс с частной переменной X. В нем напишите свой метод.

производные от этого класса ваш фактический класс. Сделайте держатель x другом фактического класса.

держатель X использует CRTP как литье (статическое литье на базу) в держателе x, чтобы превратить это в указатель на ваш фактический класс.

выставьте X-геттер из вашего X-держателя.

Я бы не беспокоился, но это лучше, чем злоупотреблять mutable и const.