[C++] The pros and cons of the Friend mechanism [Friend function, friend class]

Foreword:

        Friend is a special mechanism in C++, which can realize that in some cases, the private members of a class can be accessed by other classes or functions, so as to ensure the flexibility and maintainability of the code. This article will give a comprehensive introduction to the friend mechanism in C++, including an in-depth analysis of friend functions, friend classes, and friend mechanisms, as well as an analysis and summary of the pros and cons of friend mechanisms .

        There are a lot of code cases in this article, it is recommended to follow the code and type a few more times (practice brings true knowledge, and it is OK to figure out the basic scenarios of use)!

Table of contents

1. Friend function

Two, friend class

3. In-depth analysis of the friendship mechanism

4. Summary of pros and cons

profit:

1. Improve code flexibility

2. Realize the collaboration between different classes

3. Reduce code complexity

4. Implement class encapsulation and security control

Disadvantages:

1. Breaking the encapsulation feature of C++

2. The friendship mechanism is easy to abuse

3. The friend mechanism may lead to increased code coupling

Summarize:


1. Friend function

        A friend function is a non-member function that can directly access a private member of a class . In C++, we can declare a non-member function as a friend function by using the "friend" keyword. In a class, a friend function is not a member function of this class, but it can directly access the private members of this class. Below is a simple example where private members in class A can be accessed by function addition.

class A {
private:
    int a;
public:
    A() : a(0) {}
    friend int addition(A a1, A a2);
};

int addition(A a1, A a2) {
    return a1.a + a2.a;
}

int main() {
    A obj1, obj2;
    obj1.a = 10;
    obj2.a = 20;
    cout << "Sum of two values are : " << addition(obj1, obj2);
    return 0;
}

        In the above example, we defined a function called addition and declared class A as its friend. This function can directly access the private member a in class A and return their sum. In the main function, we can create two objects obj1 and obj2, and set values ​​for their private members a, and finally call the addition function to output their sum.

Two, friend class

        Similar to friend functions, friend classes can also directly access private members of a class. The difference is that a friend class is a class that can directly access the private members of the class it declares as a friend . Similarly, the "friend" keyword can also declare a class as a friend of another class.

The following is an example where class B is declared as a friend of class A, allowing direct access to private member a of class A.

class A {
private:
    int a;
public:
    A() : a(0) {}
    friend class B;
};

class B {
public:
    void display(A obj) {
        cout << obj.a;
    }
};

int main() {
    A obj;
    B demo;
    demo.display(obj);
    return 0;
}

        In the above example, we defined two classes A and B, and declared B as a friend class of A. The display function in class B can directly access the private member a of class A and output its value. In the main function, we can create a class A object obj and a class B object demo, and call the display function of the demo object to output the value of the private member a of obj.

        It should be noted that, unlike the friend function, the declaration of the friend class needs to be declared inside the curly braces of the class, not outside.

3. In-depth analysis of the friendship mechanism

        The friend mechanism is one of the more special and relatively seldom used features in C++. It can achieve flexible programming in some cases, but you need to pay attention to some details when using it.

        First, the friend mechanism breaks the encapsulation feature in C++ . In a class, private members are set as private to prevent objects outside the class from directly accessing them. But using the friend mechanism allows objects outside the class to directly access private members, so the friend mechanism is also considered a feature that breaks encapsulation. In order to avoid abusing the friend mechanism to destroy the encapsulation feature, we need to handle and use the friend mechanism carefully.

        Second, friend functions can be global functions, static member functions of a class, and member functions of other classes. A friend class can access private members of the class it declares as a friend. Therefore, the friendship mechanism can realize information exchange and collaboration between different classes .

When using the friend mechanism, you need to pay attention to the following points:

  1. The friend mechanism should only be used when necessary . Excessive friend declarations can break encapsulation and security, making code difficult to maintain.
  2. When defining and implementing a friend function , it takes an object of the class as a parameter and returns a value . In this way, the private members of the class can be accessed in the friend function. For example: friend int function(A obj);
  3. Try to avoid making friend declarations on entire classes . If you need to access private members of a class, you should try to encapsulate them into public interfaces instead of exposing private members.
  4. The declaration of friend functions and friend classes can be written under the public, protected or private access specifier of the class , which is determined by the requirements. But in general, it is best to write the friend declaration under the private access specifier to achieve the purpose of encapsulating private members.
  5. Friend relationships cannot be inherited, nor can they be passed . If a derived class wants to access private members of its base class, it should use virtual functions and protected member functions.

Below is the friend-related code for a comprehensive example.

#include<iostream>
using namespace std;

class B;

class A{
   private:
      int numA;
      friend void add(A, B);
   public:
      A(int n=0) : numA(n) {}
};

class B{
   private:
      int numB;
      friend void add(A, B);
   public:
      B(int n=0) : numB(n) {}
};

void add(A objectA, B objectB){
   cout << "Adding data of A and B objects to a new object C." << endl;
   cout << "Sum of private integers of A and B objects is : " << objectA.numA + objectB.numB << endl;
}

int main(){
   A objectA(7);
   B objectB(11);
   add(objectA, objectB);

   return 0;
}

        In the above example, we defined two classes A and B, both of which contain a private integer member, expressed as numA and numB. Both of these private members are accessed by another function add, so they are both declared as friend functions in the definition of class A and B. We define the add function which takes A and B objects as parameters and outputs their sum.

        In the main function, we create an A object objectA and a B object objectB and pass them to the add function. The add function will access the private members of objectA and objectB and add them to output the result.

        In addition to using friend functions, we can also use friend classes to access private members of another class. Here is an example using friend classes:

#include<iostream>
using namespace std;

class A;

class B{
   public:
      void display(A&);
};

class A{
   private:
      int numA;
   public:
      A(int n=0) : numA(n) {}
      friend class B;
};

void B::display(A &objectA){
   cout << "A::numA= " << objectA.numA << endl;
}

int main(){
   A objectA(12);
   B objectB;
   objectB.display(objectA);

   return 0;
}

        In the above example, we have defined two classes A and B, where B is defined as a friend class of A. In class A, we declare a private integer member numA, which can be accessed by class B. In class B, we define a display function that accepts the A object as a parameter and outputs its private member numA.

        In the main function, we create an A object objectA and a B object objectB, and pass objectA as a parameter to the display function of objectB. The display function will access the private member numA of objectA and output the result.

        It should be noted that in the above example, both class B and function display are declared public. This is because, if we declare them as private or protected, they will not be accessible by the code in the main function, resulting in compilation errors.

4. Summary of pros and cons

profit:

1. Improve code flexibility

        In some cases, some special requirements cannot be realized without the friend mechanism. For example, if you want to access a private member of a class through a non-member function instead of a member function, you need to use a friend function.

The following code example demonstrates how to use friend functions to access private members of a class outside the class to improve code flexibility:

#include <iostream>
using namespace std;

class A{
  private:
    int numA;
  public:
    A(int n=0) : numA(n) {}
    friend int getNumA(A);
};

int getNumA(A objectA){
  return objectA.numA;
}

int main(){
  A objectA(7);
  cout << "The private integer value of objectA is: " << getNumA(objectA) << endl; 
  return 0;
}

        In this example, we define a class A and a friend function getNumA. The getNumA function can directly access the private member numA of class A, so as to directly access the private members of the class outside the class. In this way, we can realize some special requirements without using additional public interfaces, which improves the flexibility of the code.

2. Realize the collaboration between different classes

        When implementing complex programs, different classes need to exchange information and collaborate. The information exchange and collaboration between different classes can be realized by using the friend mechanism, which simplifies program design and implementation.

The following code example demonstrates how to use friend classes to achieve cooperation between different classes:

#include <iostream>
using namespace std;

class A{
  private:
    int numA;
  public:
    A(int n=0) : numA(n) {}
    friend class B;
};

class B{
  private:
    int numB;
  public:
    B(int n=0) : numB(n) {}
    void displayNumA(A objectA){
      cout << "The value of numA is " << objectA.numA << endl;
    }
};

int main(){
  A objectA(7);
  B objectB(11);
  objectB.displayNumA(objectA);     
  return 0;
}

        In this example, we define two classes A and B, class A contains a private member numA, and class B needs to access the private member numA of A. Therefore, we declare B as a friend class of A, so that B can access A's private members. In this way, we have realized the cooperation between different classes, which facilitates the realization of the code.

3. Reduce code complexity

        Using the friend mechanism can reduce the complexity and repetition of the code, making the code easier to maintain and read.

The following code example demonstrates how to use friend classes to reduce code complexity:

#include <iostream>
using namespace std;

class A{
  private:
    int numA;
  public:
    A(int n=0) : numA(n) {}
    friend class B;
};

class B{
  private:
    int numB;
  public:
    B(int n=0) : numB(n) {}
    void displayNumA(A objectA){
      cout << "The value of numA is " << objectA.numA << endl;
    }
};

int main(){
  A objectA(7);
  B objectB(11);
  objectB.displayNumA(objectA);     
  return 0;
}

        In this example, we define two classes A and B, class A contains a private member numA, and class B needs to access the numA member of class A. If you don't use the friend class, you must first define a public interface to access the numA members of A in B, which will increase the complexity of the code. But through the friend class, B can directly access the private members of A, thus reducing the complexity of the code.

4. Implement class encapsulation and security control

        The friend mechanism can be used for class encapsulation and security control. Through the friend mechanism, only specific classes or functions can access private members, so as to realize the encapsulation and security control of classes.

The following code example demonstrates how to implement encapsulation and security control over a class:

#include<iostream>
using namespace std;

class A{
   private:
      int numA;
      friend void add(A, int);
   public:
      A(int n=0) : numA(n) {}
};

void add(A objectA, int num){
   objectA.numA += num;
}

int main(){
   A objectA(7);
   add(objectA, 11);
   return 0;
}

        In this example, we define a class A and a friend function add. In class A, numA is declared as a private member, so it is not directly accessible outside the class. But since the add function is declared as a friend function of class A, it can directly access the private member numA of A. In the main function, we create an A object and call it as a parameter of the add function, and the add function modifies the private member numA of the A object. But because the add function is just a friend function and only accesses the private member numA of the A object, the encapsulation and security control of the A class are maintained.

Disadvantages:

1. Breaking the encapsulation feature of C++

        In a class, private members are set as private to prevent objects outside the class from directly accessing them. However, using the friend mechanism allows objects outside the class to directly access private members, which destroys the encapsulation feature of C++.

The following code example demonstrates how to use friend functions to break C++'s encapsulation feature:

#include <iostream>
using namespace std;

class A{
  private:
    int numA;
  public:
    A(int n=0) : numA(n) {}
    friend void setNumA(A, int);
};

void setNumA(A objectA, int n){
  objectA.numA = n;
}

int main(){
  A objectA(7);
  setNumA(objectA, 11);
  cout << "The private integer value of objectA is: " << objectA.getNumA() << endl;  
  return 0;
}

        In this example, we define a class A and a friend function setNumA, which can directly access the private member numA of A. But through the friend function setNumA, users can bypass the public interface provided by class A and directly modify its private member numA, thus destroying the encapsulation feature of class A and affecting the stability and maintainability of the code.

2. The friendship mechanism is easy to abuse

        Excessive friend declarations can break encapsulation and security, making code difficult to maintain. Therefore, the friend mechanism should only be used when necessary. Otherwise, the maintenance cost of the program will increase, and the security and stability of the program will also be reduced.

The following code example demonstrates how to abuse the friend mechanism using friend functions:

#include<iostream>
using namespace std;

class A{
   private:
      int numA;
      friend void add(A&, int);
   public:
      A(int n=0) : numA(n) {}
      int getNum() { return numA; }
};

void add(A& objectA, int num){
   objectA.numA += num;
}

int main(){
   A objectA(7);
   add(objectA, 11);
   cout << "The integer value of numA is : " << objectA.getNum() << endl;
   return 0;
}

        In this example, we define a class A and a friend function add. The add function modifies the private member numA of A by reference. But the add function can directly access the private members of A, which easily leads to the abuse of the friend mechanism, thus affecting the clarity and readability of the code.

3. The friend mechanism may lead to increased code coupling

        The friendship mechanism may lead to an increase in the coupling between different classes, thereby affecting the reusability and scalability of the program. The friend mechanism needs to be used carefully to avoid increasing the coupling of the code.

The following code example demonstrates how to use friend functions to increase code coupling:

#include<iostream>
using namespace std;

class A{
   private:
      int numA;
      friend void add(A&, int);
   public:
      A(int n=0) : numA(n) {}
      void displayNumA() { cout << "The integer value of numA is : " << numA << endl;}
};

void add(A& objectA, int num){
   objectA.numA += num;
}

class B{
   public:
      void display(A& objectA){
         objectA.displayNumA();
      }
};

int main(){
   A objectA(7);
   B objectB;
   add(objectA, 11);
   objectB.display(objectA);
   return 0;
}

        In this example, we define a class A and a friend function add and class B and a display function in class B. Class B performs some operations on class A, so the coupling between the two classes is increased. Such a code structure may lead to too close dependencies between classes, thus affecting the stability and maintainability of the code.

Summarize:

        Friend means that in a class, another class or function can directly access the private members of the class declared as a friend . The friend mechanism can make the code more flexible, and realize information exchange and collaboration between different classes without destroying the encapsulation and security. However, excessive friend declarations break encapsulation and security, and abuse should be avoided .

        There are two types of friend mechanisms: friend functions and friend classes . A friend function is a non-member function that can directly access a private member of a class. A friend class is a class that can access the private members of the class it declares as a friend.

        It should be noted that the friendship relationship cannot be inherited and transmitted, try to avoid making friend declarations for the entire class. The declarations of friend functions and friend classes can be written under the public, protected or private access specifiers of the class, but in general, it is best to write the friend declarations under the private access specifiers to achieve the purpose of encapsulating private members .

        In practical applications, the friend mechanism should be used cautiously, only for necessary cases, and encapsulate private members into public interfaces as much as possible. The friend mechanism is one of the important features in C++, mastering the friend mechanism can make us do C++ programming better.

Guess you like

Origin blog.csdn.net/crr411422/article/details/130946626