const
означает, что вы обещаете не изменять переменную. Это все еще можно изменить.
class A {
public:
A(const int& a);
int getValue() const;
void setValue(int b);
private:
const int& a;
};
A::A(a) : a(a) {}
int A::getValue() const {
return a;
}
void A::setValue(int b) {
a = b; // error
}
int main() {
int my_a = 0;
A a(my_a);
std::cout << a.getValue() << std::endl; // prints 0
my_a = 42;
std::cout << a.getValue() << std::endl; // prints 42
}
Нет способа A::*
может измениться a
, но main
может. Это очень похоже на C и C ++.
В C ++ есть пара (ограниченных) способов обхода const
, которые должны препятствовать программистам отбрасывать const
ненадлежащим образом.
Пройдите такой урок.
class A {
public:
A();
int getValue();
private:
static int expensiveComputation();
int cachedComputation;
};
A::A() : cachedComputation(0) {}
A::getValue() {
if (cachedComputation == 0)
cachedComputation = expensiveComputation();
return cachedComputation;
}
cachedComputation
неявно означает this->cachedComputation
. Имейте это в виду.
int main() {
A a1;
const A a2;
std::cout << a1.getValue() << std::endl;
std::cout << a2.getValue() << std::endl; // error
}
a2.getValue()
недопустимо, потому что не const
метод вызывается для const A a2
. Можно отбросить const
-несс ...
std::cout << ((A&)a2).getValue() << std::endl; // C-style cast
std::cout << const_cast<A&>(a2).getValue() << std::endl; // C++-style cast
Второй вариант предпочтительнее, потому что компилятор проверит, что преобразуется только const
, и ничего больше. Тем не менее, это все еще не идеально. Вместо этого в класс должен быть добавлен новый метод.
class A {
public:
int getValue() const;
};
A::getValue() const {
if (cachedComputation == 0)
cachedComputation = expensiveComputation(); // error
return cachedComputation;
}
Теперь есть метод const
, так что a2.getValue()
хорошо. Однако завершающий const
означает, что методу присваивается указатель const A *this
, а не A *this
, как обычно, что делает this->cachedComputation
a const int &
, который нельзя изменить.
const_cast
может применяться внутри метода, но лучше было бы изменить объявление этого одного члена.
class A {
private:
mutable int cachedComputation;
};
Теперь, даже с const A *this
, this->cachedComputation
может быть видоизменен без приведения.