struct Fooo
{
void func() const {}
protected:
void func() {}
};
...
Fooo fooo;
fooo.func();
Компилятор говорит, что func недоступен, потому что он защищен. Почему это работает так? Я ожидал, что неконстантная версия просто не будет видна и будет вызвана константная.
Я столкнулся с этим, когда класс предоставлял константный доступ к члену, а также имел неконстантную версию функции для внутреннего использования. Другой случай, когда создается «защищенный изменяемый» базовый класс со всеми неконстантными методами доступа, объявленными защищенными, чтобы один класс мог быть производным от него и сохранять свои данные неизменяемыми для общедоступного, а другой производный класс сделал геттеры доступными, введя в общедоступную область видимости. , лайк Base::getterFunc;
.
class Base
{
int a;
public:
const auto& getA() const { return a; }
protected:
auto& getA() { return a; }
};
class PublicAccess : public Base
{
public:
Base::getA;
};
class KeepProtected : public Base
{
};
В одном конкретном случае Vector
и NormalizedVector
произошли от VectorBase
. NormalizedVector
может мутировать свои элементы, но не случайно по воле общественности.
В любом случае, примеры не суть, просто интересно, в чем логика этой недоступности, когда защищенную версию можно просто рассматривать как не существующую и выбирать константную версию.
@Someprogrammerdude Нет, все наоборот. :)
Именно так работает C++. Доступ к нему проверяется после выбора вызываемой функции.
Все функции-члены класса «просматриваются» и проверяются как кандидаты на вызов. После определения лучшего кандидата проверяется его доступность. Если выбранная функция недоступна, это диагностируемая ошибка (как вы видите).
Если бы список кандидатов был сокращен, чтобы удалить недоступную функцию, это вызвало бы еще большую путаницу. Представьте, что определение класса отредактировано, чтобы создать предыдущую public
функцию private
. Тогда ожидается, что диагностика (для кода, не являющегося членом и не являющегося другом, вызывающего эту функцию) будет касаться недоступной функции. Если вместо этого была вызвана другая функция, код будет построен без ошибок, но его поведение может измениться радикальным и неожиданным образом, и [некоторое время спустя, когда станет понятно, что что-то не так], проблему может быть довольно сложно обнаружить и устранить. правильный.
Просмотр спецификаторов доступа — это последнее, что нужно сделать. Сначала выбирается неконстантная версия, а затем проверяется доступ. Почему это так? Я полагаю, что это сделано для упрощения процесса выбора функции для вызова. Если вы считаете это необоснованным, попробуйте прочитать соответствующую часть стандарта. Вскоре вы поймете, что поиск имени уже является очень сложным процессом.
Обходной путь — переименовать защищенный func
во что-то другое, например func_ex
или func_impl
или func_prot
для использования API защищенной иерархии, и иметь константу func
для общедоступного API, обращенного к пользователю.
Я ожидал, что неконстантная версия просто не будет видна
Это твоя ошибка. Спецификаторы доступа (public
, private
, protected
) фактически не меняют то, какие члены рассматриваются или учитываются при разрешении перегрузки.
Единственный эффект, который они оказывают, — это вызвать ошибку компиляции, если они названы или выбраны при разрешении перегрузки. Вы не можете использовать их, чтобы «скрыть» функции-члены и заставить разрешение перегрузки вести себя по-разному в разных контекстах. Разрешение перегрузки будет работать одинаково во всех контекстах. Вам следует давать функциям для внутреннего использования имена, отличные от имен во внешнем интерфейсе, и не полагаться на разрешение перегрузки.
Или, говоря немного по-другому, если у вас компилируется программа, вы можете заменить все private
и protected
на public
, и программа (за некоторыми небольшими исключениями) все равно будет работать точно так же, как и раньше. Они существуют только для того, чтобы избежать ошибок, например. используя член, который не предназначен для внешнего использования.
Функции с квалификаторами
const
можно вызывать только для объектовconst
.