const
относится к семантике программы, а не к деталям реализации. Вы должны пометить функцию-член const
, когда она не изменяет видимое состояние объекта, и должна вызываться для объекта, который сам по себе const
. В функции-члене const
класса X
тип this
равен X const *
: указатель на постоянный X
объект. Таким образом, все переменные-члены фактически const
внутри этой функции-члена (кроме mutable
единиц). Если у вас есть объект const
, вы можете вызывать только const
функции-члены на нем.
Вы можете использовать mutable
, чтобы указать, что переменная-член может измениться даже внутри const
функции-члена. Это обычно используется для идентификации переменных, используемых для кэширования результатов, или для переменных, которые не влияют на фактическое наблюдаемое состояние, таких как мьютексы (вам все еще нужно заблокировать мьютекс в функциях-членах const
) или использовать счетчики.
class X
{
int data;
mutable boost::mutex m;
public:
void set_data(int i)
{
boost::lock_guard<boost::mutex> lk(m);
data=i;
}
int get_data() const // we want to be able to get the data on a const object
{
boost::lock_guard<boost::mutex> lk(m); // this requires m to be non-const
return data;
}
};
Если вы удерживаете данные указателем, а не напрямую (включая интеллектуальные указатели, такие как std::auto_ptr
или boost::shared_ptr
), тогда указатель становится const
в функции-члене const
, но не указанными данными, так что вы можете изменить указанные данные.
Что касается кеширования: обычно компилятор не может этого сделать, потому что состояние может меняться между вызовами (особенно в моем многопоточном примере с мьютексом). Однако, если определение встроено, то компилятор может вставить код в вызывающую функцию и оптимизировать то, что он там видит. Это может привести к тому, что функция эффективно будет вызываться только один раз.
В следующей версии C ++ Standard (C ++ 0x) будет новое ключевое слово constexpr
. Функции с тегом constexpr
возвращают постоянное значение, поэтому результаты могут быть кэшированы. Существуют ограничения на то, что вы можете сделать в такой функции (для того, чтобы компилятор мог проверить этот факт).