Можно ли заблокировать переменную, чтобы предотвратить ее изменения в 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.