Почему С++ не ссылается на const, когда метод const является общедоступным, а не const const защищен?

Я создал класс с двумя методами get, один const и один не const. Метод const является общедоступным, поэтому пользователи могут запрашивать вектор. Метод non-const защищен, поэтому я могу использовать его для изменения необходимых мне данных.

Однако, когда я пытаюсь использовать класс и вызываю метод get, компилятор жалуется, что метод non-const защищен. Вместо этого я должен использовать const_cast, чтобы передать объект в const, поэтому я могу вместо этого использовать открытый метод.

Есть ли способ решить это? Почему компилятор не выполнил сам бросок, поскольку существует общедоступный метод? Если я удалю защищенную версию и просто оставлю ее const, она будет работать отлично, поэтому в этой ситуации она будет выполнена. Кастинг в const всегда безопасен. Это устранение неполадки, которая является проблемой.

Ответ 1

Компилятор рассматривает доступность после того, как он решает, какую функцию-член он хочет вызвать. То есть защищенные и частные функции все еще видны, хотя они недоступны.

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

Как надуманный пример, здесь довольно ужасный интерфейс класса:

public:
    // Returns the amount of change tendered for this transaction.
    MoneyAmount change() const;

private:
    // Account for a change of currency. Charges standard moneychanger fee.
    MoneyAmount change(Currency toCurrency = Currency::USD);

Если недоступные функции были удалены из разрешения перегрузки, клиентский код мог бы вызвать change() просто отлично. И если позже вторая функция change(Currency) была обнародована, а первая удалена, этот код внезапно неожиданно вызовет другую функцию с совершенно другой целью. Существующие правила не позволяют изменять спецификатор доступа из-за изменения поведения компиляционной программы.

Ответ 2

Контроль доступа элемента - это последнее, что происходит при вызове функции-члена. Это происходит после поиска имени, вычитания аргумента шаблона, разрешения перегрузки и т.д. Причина, по которой это делается в последнее время, заключается в том, что было решено, что изменение контроля доступа для члена не должно внезапно изменять выполнение клиентского кода.

Представьте, что доступ был проверен до разрешения перегрузки, и вы использовали библиотеку и определенную функцию-член в этой библиотеке. Затем авторы библиотеки сделали функцию частной. Внезапно ваш код начинает использовать другую перегрузку и ведет себя совершенно по-другому. Авторы библиотеки, вероятно, предполагали, что кто-либо, использующий эту перегрузку функции, должен прекратить ее использовать, но они не собирались менять код. Однако, поскольку стандарт фактически определен, ваш код теперь начнет давать вам ошибку для использования частного участника, а не вести себя по-другому.

Решение состоит в том, чтобы просто изменить имя вашей защищенной функции-члена, чтобы оно не учитывалось.

Ответ 3

В С++ выбор метода (перегрузочное разрешение) происходит до того, как будет рассмотрен контроль доступа к публичному/частному доступу.

Ответ 4

Вместо метода non const getter используйте вместо этого метод защищенного setter (или элемент данных).

Не имеет значения, если у вас есть. как

class A {
    SomeType foo_;
protected:
    SomeType& foo() { return foo_; }

public:
    const SomeType& foo() const { return foo_; }
};

или

class A {
protected:
    SomeType foo_;

public:
    const SomeType& foo() const { return foo_; }
};

Ответ 5

Это поведение природы С++, если код вызывающего, объект класса не является константой, поэтому не-преобразование, которое определено как защищенное. Вам нужно определить объект класса как const или использовать const-cast на объекте класса, что приведет к вызову версии const метода.

#include <iostream>
class Foo {
    public:
        const void bar() const { std::cout << " const version called\n";}  
    protected:
        void bar() { std::cout << " non const version called\n";}  
};

int main(int argc, char** argv)
{
    const Foo c;
    c.bar(); // -> work

    Foo c1;
    c1.bar(); // compiler complain -> void Foo::bar() is protected
    const_cast<const Foo&>(c1).bar(); // fine 
}