Страницы

Поиск по вопросам

пятница, 24 января 2020 г.

Смысл от дружественных функций в C++

#ооп #классы #cpp


Какой смысл несут дружественные функции для класса и дружественные классы для класса:
class B;

// class A definition
class A {
  int n1, n2;

  friend void print_fields(A a);  // практический смысл?
  friend class B; // практический смысл?

public:
  set_fields(n_1,n_2) {
    n1 = n_1;
    n2 = n_2;
  }
};

void print_fields(A a) {
  cout << a.n1 << " " << a.n2 << endl;
}

Зачем так делать:
   friend void print_fields(A a);

Если данный метод и так является фактически публичным членом класса( раз он дружественный,
то доступен отовчюду ) и, соответственно, тмеет прямой доступ к начинки класса?
Это тоже не совсем понятно:
  friend class B;

Ведь класс А можно "запротектить" (protected) и все будет ок. Объясните, пожалуйста.    


Ответы

Ответ 1



Иногда действительно возникает необходимость из вне иметь доступ к закрытым полям данных твоего класса. В этом случае без друзей не обойтись. Вот пример - ты написал класс описывающий игрового юнита. Этот класс содержит внутреннее представление m_HP и открытый интерфейс Injure - нанести урон, Heal - лечить и IsAlive - проверка, жив ли юнит. class Unit { public: friend void TestUnit(); Unit(unsigned maxHP) : m_maxHP(maxHP) , m_HP(maxHP) {}; void Injure(unsigned val) { m_HP -= val; if( m_HP < 0 ) { m_HP = 0; } }; void Heal(unsigned val) { m_HP += val; if( m_HP > m_maxHP ) { m_HP = m_maxHP; } } bool IsAlive() const { return m_HP > 0; } private: unsigned m_maxHP; int m_HP; }; Ты решаешь обернуть функционал класса юнит тестами, что бы быть уверенным в том, что функции void Injure(unsigned val) и void Heal(unsigned val) работают корректно: void TestUnit() { Unit unit(100); unit.Injure(10); assert(unit.m_HP == 90); // check private data field unit.Heal(20); assert(unit.m_HP == 100); // check private data field } int main() { TestUnit(); } Как видишь, написание теста было бы невозможно без обращения к внутреннему представлению класса. Именно для этого мы объявили функцию void TestUnit() дружественной к классу Unit Upd: Еще один пример использования дружественных функций при проектировании собственного класса и обеспечения его функциональности. Ниже приведен очень простой пользовательский класс оборачивающий целое число. Для помещения экземпляров данного класса в выходной поток самым естественным образом необходимо определить функцию operator<< не являющуюся экземпляром класса #include class WrappedInt { public: explicit WrappedInt(int val) : m_value(val) {} friend std::ostream& operator<<(std::ostream& os, const WrappedInt& val); private: int m_value; }; std::ostream& operator<<(std::ostream& os, const WrappedInt& val) { os << val.m_value; return os; } а для того, что бы эта функция имела доступ к закрытым полям класса, таким как m_value, мы и делаем ее дружественной по отношению к классу WrappedInt.

Комментариев нет:

Отправить комментарий