Почему функция участника PRIVATE не может быть функцией друга другого класса?
class x
{
void xx() {}
};
class y
{
friend void x::xx();
};
Это приводит к ошибке типа
error: функция friend 'xx' является частным членом 'x'
Почему я не могу объявить частную функцию-член как друга другого класса?
Ответы
Ответ 1
[class.friend]/9:
Название, назначенное декларацией друга, должно быть доступно в область действия класса, содержащего декларацию друга.
Причина довольно проста; Члены private
должны соблюдать ясное и определенное правило:
Член класса может быть
-
private
; то есть его имя может использоваться только членами и друзьями класса, в котором он объявлен.
Разрешить имена частных членов в объявлениях внутри несвязанных классов будет нарушать это правило: он позволяет другому классу зависеть от детализации реализации, не будучи явно разрешенным. Это становится проблематичным, например, при изменении имени частного лица, типа или подписи или его полного удаления; который предназначен для того, чтобы не нарушить интерфейс этого класса.
Это можно обойти, сделав все x
другом y
:
class x {
void xx() {}
};
class y {
friend x;
};
Демо.
Ответ 2
Предполагается, что идея x::xx
private
заключается в том, что x::xx
представляет собой деталь реализации, на которую не следует полагаться другими классами. Это не просто означает, что x::xx
нельзя вызывать другими классами, это означает, или, скорее, это должно означать, что, например, переименование x::xx
в x::xy
не должно нарушать ничего, кроме самого класса и друзей класса.
В вашем случае переименование x::xx
до x::xy
приведет к ошибке класса y
, хотя это не является другом x
.
Чтобы избежать этого, сделайте y
другом x
, так что y
может получить доступ к x
private
членам. Затем он может объявить x::xx
как friend
.
(Примечание: более прямой ответ на вопрос "Почему компилятор не разрешает это?" - это "Потому что стандарт не позволяет этого". Это, естественно, приводит к следующему вопросу "Почему стандарт не разрешите это?". Я пытаюсь ответить на этот последующий вопрос.)