What is the meaning of the friendly functions for the class and the friendly classes for the class:

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; } 

Why do so:

  friend void print_fields(A a); 

If this method is actually a public member of a class (since it is friendly, then it is available from the class) and, accordingly, does it have direct access to the class stuffing?

This is also not entirely clear:

  friend class B; 

After all, class A can be “protected” (protected) and everything will be ok. Explain, please.

  • one
    > If this method is actually no public member of the class, it is not a method and is not a public member of the class. This is an external function. But why did she need access to the class guts - a separate question. For example, in this way it is necessary to implement operator overloading between different classes. That is, say, so that you can do not only CComplex + CComplex, but also CComplex + CFloat, and CFloat + CComplex. - gecube
  • 2
    Secondly, public / protected / private have a very rough scope. Those. public - available to ALL, protected - available to heirs, and private - available ONLY to class member functions. A friend allows point-to-point access without bulging into public or variables, or setters for them. - gecube
  • one
    Also, friendship allows you to complement the functionality of library classes whose code is undesirable for modification. - gecube
  • @gecube, thanks for the explanation! For the time being, in practice, I most often encounter an overload of the Output-stream operator << through a friendly method. - Free_man am
  • one
    If you use a library written by someone, then, in general, only the interface provided by the classes of this library is at your disposal, including only those friend functions that are provided by the developer of this library. - carapuz

1 answer 1

Sometimes it really becomes necessary to have access to the private data fields of your class from outside. In this case, no friends can not do.

Here is an example - you wrote a class describing a game unit. This class contains the internal representation of m_HP and the open interface Injure — cause damage, Heal — treat, and IsAlive — check whether the unit is alive.

 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; }; 

You decide to wrap the functionality of the class unit with tests, to be sure that the void Injure (unsigned val) and void Heal (unsigned val) functions work correctly:

 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(); } 

As you can see, writing a test would be impossible without reference to the internal representation of the class. That is why we declared the void TestUnit () function to be class-friendly Unit

Upd:

Another example of the use of friendly functions in the design of its own class and ensure its functionality. Below is a very simple custom class wrapping an integer. To put instances of this class into the output stream, it is most natural to define the operator << function that is not an instance of the class.

 #include <iostream> 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; } 

and in order for this function to have access to the private fields of a class, such as m_value, we make it friendly to the WrappedInt class.