Проблема с постоянным / неконстантным разрешением перегрузки - PullRequest
9 голосов
/ 05 июня 2011

У меня есть класс, который выглядит примерно так:

class ClassA
{
  public:
    float Get(int num) const;
  protected:
    float& Get(int num);
}

Вне класса я вызываю функцию Get ().

float foo = classAInstance.Get(i);

Я ожидаю, что это вызовет публичную версию, но вместо этого Visual Studio выдает ошибки:

error C2248: 'ClassA::Get' : cannot access protected member declared in class 'ClassA'

При комментировании защищенной перегрузки и удалении всех ссылок на нее код компилируется.

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

Ответы [ 2 ]

7 голосов
/ 05 июня 2011

Это правда, разрешение перегрузки происходит перед проверкой доступности.Раздел 13.3 стандарта ([over.match]) гласит:

Разрешение перегрузки - это механизм выбора наилучшей функции для вызова, учитывая список выражений, которые должны быть аргументами вызова и наборафункций-кандидатов, которые могут быть вызваны на основе контекста вызова.Критериями выбора наилучшей функции являются количество аргументов, то, насколько хорошо аргументы соответствуют списку параметров-типов функции-кандидата, насколько хорошо (для нестатических функций-членов) объект соответствует неявному параметру объекта и некоторые другиесвойства функции-кандидата.[Примечание: функция, выбранная по разрешению перегрузки, не гарантированно соответствует контексту.Другие ограничения, такие как доступность функции, могут сделать ее использование в контексте вызова некорректным.- конец примечания]

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


Обратите внимание, это иногда полезно, например:

class Blah
{
    const std::string& name_ref;

    Blah(const char*) = delete;

public:
    Blah(const std::string& name) : name_ref(name) {}

    void do_something_with_name_ref() const;
};

std::string s = "Blam";
Blah b(s); // ok

Обратите внимание, что name_ref будет считываться только из, поэтому целесообразно сделать его const.Тем не менее, ссылки const могут привязываться к временным файлам, а привязка name_ref к временным объектам будет зависать, что приведет к неопределенному поведению в do_something_with_name_ref().

Blah c("Kablooey!"); // would be undefined behavior
                     // the constructor overload makes this a compile error

Перегрузка частного конструктора предотвращает временнуюstd::string от неявного построения и связывания.

5 голосов
/ 05 июня 2011

Сначала выполняется разрешение перегрузки, а позже - проверка доступа.

Если у вас есть как постоянная, так и неконстантная перегрузка, это разрешается константностью объекта, для которого вызывается функция.

...