C++ — функция недоступна, если неконстантная версия существует как защищенная

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 может мутировать свои элементы, но не случайно по воле общественности.

В любом случае, примеры не суть, просто интересно, в чем логика этой недоступности, когда защищенную версию можно просто рассматривать как не существующую и выбирать константную версию.

Функции с квалификаторами const можно вызывать только для объектов const.

Some programmer dude 02.09.2024 06:55

@Someprogrammerdude Нет, все наоборот. :)

HolyBlackCat 02.09.2024 06:56

Именно так работает C++. Доступ к нему проверяется после выбора вызываемой функции.

HolyBlackCat 02.09.2024 06:56

Все функции-члены класса «просматриваются» и проверяются как кандидаты на вызов. После определения лучшего кандидата проверяется его доступность. Если выбранная функция недоступна, это диагностируемая ошибка (как вы видите).

Peter 02.09.2024 06:58

Если бы список кандидатов был сокращен, чтобы удалить недоступную функцию, это вызвало бы еще большую путаницу. Представьте, что определение класса отредактировано, чтобы создать предыдущую public функцию private. Тогда ожидается, что диагностика (для кода, не являющегося членом и не являющегося другом, вызывающего эту функцию) будет касаться недоступной функции. Если вместо этого была вызвана другая функция, код будет построен без ошибок, но его поведение может измениться радикальным и неожиданным образом, и [некоторое время спустя, когда станет понятно, что что-то не так], проблему может быть довольно сложно обнаружить и устранить. правильный.

Peter 02.09.2024 07:03

Просмотр спецификаторов доступа — это последнее, что нужно сделать. Сначала выбирается неконстантная версия, а затем проверяется доступ. Почему это так? Я полагаю, что это сделано для упрощения процесса выбора функции для вызова. Если вы считаете это необоснованным, попробуйте прочитать соответствующую часть стандарта. Вскоре вы поймете, что поиск имени уже является очень сложным процессом.

john 02.09.2024 07:14

Обходной путь — переименовать защищенный func во что-то другое, например func_ex или func_impl или func_prot для использования API защищенной иерархии, и иметь константу func для общедоступного API, обращенного к пользователю.

Eljay 02.09.2024 13:38
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
7
73
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я ожидал, что неконстантная версия просто не будет видна

Это твоя ошибка. Спецификаторы доступа (public, private, protected) фактически не меняют то, какие члены рассматриваются или учитываются при разрешении перегрузки.

Единственный эффект, который они оказывают, — это вызвать ошибку компиляции, если они названы или выбраны при разрешении перегрузки. Вы не можете использовать их, чтобы «скрыть» функции-члены и заставить разрешение перегрузки вести себя по-разному в разных контекстах. Разрешение перегрузки будет работать одинаково во всех контекстах. Вам следует давать функциям для внутреннего использования имена, отличные от имен во внешнем интерфейсе, и не полагаться на разрешение перегрузки.

Или, говоря немного по-другому, если у вас компилируется программа, вы можете заменить все private и protected на public, и программа (за некоторыми небольшими исключениями) все равно будет работать точно так же, как и раньше. Они существуют только для того, чтобы избежать ошибок, например. используя член, который не предназначен для внешнего использования.

Другие вопросы по теме