Друг класс в C++
Здесь я не очень хорошо понимаю концепцию, или я прав.... Итак, давайте возьмем этот пример класса "друг" здесь:
class MyClass{
friend class AnotherClass;
private:
int secret;
}
class AnotherClass{
public:
void getSecret(MyClass mc){
return mc.secret;
}
}
Так что да... в приведенном выше коде это на самом деле будет работать, если вы это сделаете... но в целом, почему вы не можете все время использовать методы получения и установки вместо класса друга? Является ли причиной использования класса "друг" из-за "утомительности"?
3 ответа
friend
для случаев, когда вы не хотите показывать getters / setters / internals всем, а только одному классу. Так что это инструмент для инкапсуляции.
Например, если вы предоставили общественности getSecret
в MyClass
каждый может иметь доступ к этой закрытой переменной, даже если он не должен знать об этом. Это нарушает инкапсуляцию. friend
есть, чтобы решить эту проблему, так что только те классы, которые должны знать о secret
иметь доступ к нему.
Как сказал @nicomp, "это все равно, что дать физическому другу ключ от вашего дома, но вы не знаете, что они с ним сделают". Так что friend
класс имеет неограниченный доступ ко всем внутренним компонентам класса, с которым он дружит. Это прискорбно, но ключ (без каламбура) здесь состоит в том, чтобы классы были как можно меньше, чтобы это не стало проблемой, что также соответствовало бы принципу единой ответственности.
Публичный получатель или установщик разрешает доступ кому угодно. У них есть несколько применений, в частности, для поддержки инвариантов классов при изменении какого-либо свойства, но пара getter / setter, которая выглядит как следующий код, не лучше открытых переменных-членов:
class A {
public:
int getX() const { return x; };
void setX(int x_) { x = x_; };
private:
int x;
};
getX()
а также setX()
функции делают только доступ к x
, Каждый может их использовать, поэтому любой может изменить значение x
, Тогда нет смысла делать это приватным.
Если вместо этого нужно изменить только некоторые классы или функции x
, вы можете сделать их друзьями класса A
, Это ограничивает доступ только тем друзьям, а не дает его всем.
В качестве таких, friend
это инструмент для инкапсуляции, позволяющий инкапсуляции быть шире, чем "просто мой собственный класс" (частные члены) или "только мой класс и классы, которые происходят от него" (защищенные члены). Друг не обязательно должен находиться в одной иерархии классов (он вовсе не должен быть классом; функции могут быть друзьями), но он все же позволяет вам ограничивать доступ только к тем вещам, которые действительно в нем нуждаются.
Обратите внимание, что, как и методы получения и установки, его следует использовать с осторожностью. Инкапсуляция - это хорошо, и, по возможности, частные члены вашего класса должны оставаться именно такими - частными. friend
это инструмент, который позволяет вам выборочно предоставлять доступ, но вы всегда должны тщательно обдумывать, нужно ли предоставлять этот доступ, или же вместо этого лучше использовать функцию / класс, который нуждается в ней, как член вашего класса.
Не забывайте про тестирование...
Дружественные классы / методы могут довольно успешно использоваться для тестирования промежуточных состояний в рамках функциональности класса.
Они также могут быть полезны для некоторых типов конструкторов копирования, когда копируемый класс не является прямым предком целевого класса.
Рассмотрим следующий вариант использования, с которым я столкнулся в последнее время: я переделал некоторый код из одного класса в другой. Этот новый класс должен был получить доступ к членам из исходного класса, но я не хотел предоставлять это через общедоступные методы получения, чтобы другие клиенты не возились с ними. В этом случае я действительно приветствовал механизм дружбы C++.
Однако эти варианты использования встречаются очень редко (надеюсь, в противном случае, возможно, что-то не так в вашей архитектуре программного обеспечения), и я стараюсь избегать этого столько, сколько могу, так как это самая жесткая форма связи.