Если у меня есть два метода — один общедоступный, другой защищенный, который возвращает ссылку на один и тот же член, я получаю следующую ошибку компиляции:
'Server::getManager': cannot access protected member declared in class 'Server'
Когда я закомментирую защищенную функцию, код работает. Не могли бы вы сообщить, почему это происходит? Почему компилятор не может найти открытую функцию для того же члена?
class Manager
{
};
class Server
{
public:
const Manager & getManager() const { return m_man; }
protected:
Manager & getManager() { return m_man; } // <-- after removing this method I get no compilation error
private:
Manager m_man;
};
int main()
{
Server s;
const Manager& m = s.getManager();
return 0;
}
Почему компилятор не может найти открытую функцию для того же члена?
Это не проблема. Компилятор находит и то и другое функции и выполняет разрешение перегрузки, чтобы определить, какой из них является наиболее подходящим кандидатом. Два кандидата:
Manager& getManager() // protected
Manager const& getManager() const // public
Для функций-членов существует неявный параметр первого объекта, который является экземпляром самого класса. В этом случае две функции становятся:
getManager(Server& ) // protected
getManager(Server const& ) // public
Мы вызываем его на объекте (s
) это не const
, Оба кандидата жизнеспособны, но public
кандидат берет ссылку на Больше резюме-квалифицированный объект, чем protected
кандидат — так что это менее предпочтительно. Стандарт находится в [over.ics.rank]:
Стандартная последовательность преобразования S1 является лучшей последовательностью преобразования, чем стандартная последовательность преобразования
S2 если
— S1 и S2 являются привязками ссылок (8.5.3), и типы, на которые ссылаются ссылки, одинаковы
type за исключением cv-квалификаторов верхнего уровня и типа, к которому относится ссылка, инициализированная S2
является более квалифицированным по cv, чем тип, к которому относится ссылка, инициализированная S1.
В результате protected
Кандидат является предпочтительным, так что это тот, который называется.
К сожалению это protected
так что называть это плохо сформировано. Контроль доступа проверяется после разрешения перегрузки. Так что вам придется как-то реструктурировать свою программу. Вы могли бы просто бросить s
в const
:
const Manager& m = const_cast<Server const&>(s).getManager();
Это сделало бы protected
кандидат нежизнеспособный.
Других решений пока нет …