Можно ли указать закрытую переменную-член public только для операций const?

У меня есть переменная-член, 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 операции, все без необходимости требовать от пользователя пройти процедуры доступа?

4

Решение

Нет, нет возможности ограничить изменение только членами. private ограничивает весь доступ к имени; const мешает модификации везде.

Есть несколько гротескных альтернатив (например, const ссылка или использование const_cast), но функция доступа является самым простым и идиоматичным способом сделать это. Если он встроенный, как в вашем примере, то его использование должно быть таким же эффективным, как прямой доступ.

9

Другие решения

Большинство инженеров предпочитают использовать методы доступа, но если вы действительно хотите взломать, вы можете сделать что-то вроде этого:

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;
}
};
10

Здесь многое зависит от намерения разоблачить включенное состояние, но мой общий совет будет избегать разоблачения совсем.

Обычное использование вашего 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,

Короче говоря, это обычно плохой дизайн. Просто не делай этого.

5
По вопросам рекламы [email protected]