У меня есть переменная-член, enabled_m
, чье значение зависит от ряда переменных. Поскольку эти инварианты должны поддерживаться классом, я хочу, чтобы это было private
:
class foo_t
{
public:
void set_this(...); // may affect enabled_m
void set_that(...); // may affect enabled_m
void set_the_other_thing(...); // may affect enabled_m
bool is_enabled() const { return enabled_m; }
private:
bool enabled_m;
};
Что работает, но на самом деле мое намерение состоит в том, чтобы потребовать от пользователя foo_t
пройти через класс модифицировать enabled_m
, Если пользователь хочет просто читать enabled_m
, это должна быть допустимая операция:
bool my_enabled = foo.enabled_m; // OK
foo.enabled_m = my_enabled; // Error: enabled_m is private
Есть ли способ сделать enabled_m
public
за const
операции и private
для неconst
операции, все без необходимости требовать от пользователя пройти процедуры доступа?
Нет, нет возможности ограничить изменение только членами. private
ограничивает весь доступ к имени; const
мешает модификации везде.
Есть несколько гротескных альтернатив (например, const
ссылка или использование const_cast
), но функция доступа является самым простым и идиоматичным способом сделать это. Если он встроенный, как в вашем примере, то его использование должно быть таким же эффективным, как прямой доступ.
Большинство инженеров предпочитают использовать методы доступа, но если вы действительно хотите взломать, вы можете сделать что-то вроде этого:
class AccessControl
{
private:
int dontModifyMeBro;
public:
const int& rDontModifyMeBro;
AccessControl(int theInt): dontModifyMeBro(theInt), rDontModifyMeBro(dontModifyMeBro)
{}
// The default copy constructor would give a reference to the wrong variable.
// Either delete it, or provide a correct version.
AccessControl(AccessControl const & other):
dontModifyMeBro(other.rDontModifyMeBro),
rDontModifyMeBro(dontModifyMeBro)
{}
// The reference member deletes the default assignment operator.
// Either leave it deleted, or provide a correct version.
AccessControl & operator=(AccessControl const & other) {
dontModifyMeBro = other.dontModifyMeBro;
}
};
Здесь многое зависит от намерения разоблачить включенное состояние, но мой общий совет будет избегать разоблачения совсем.
Обычное использование вашего is_enabled
будет что-то вроде:
if (f.is_enabled())
f.set_this(whatever);
На мой взгляд, почти всегда лучше просто позвонить set_this
и (если клиент заботится) вернуть ему значение, чтобы указать, успешно ли это выполнено, поэтому код клиента становится примерно таким:
if (!f.set_this(whatever))
// deal with error
Хотя это может показаться тривиальной разницей, когда вы начинаете заниматься многопоточным программированием (для одного основного примера), эта разница становится абсолютно критической. В частности, первый код, который проверяет включенное состояние, а затем пытается установить значение, подчиняется условию гонки — enabled
состояние может меняться между вызовами is_enabled
и призыв к set_this
,
Короче говоря, это обычно плохой дизайн. Просто не делай этого.