Example of C++ middle friend

  • 2020-05-27 06:47:51
  • OfStack

Example of C++ middle friend

Although friends are granted external access to private parts of a class, they do not contradict object-oriented programming ideas; Instead, he increased the flexibility of public interfaces.

1. The metaclass

The youyuan declaration can be in the public or private protected parts, and its location does not matter

I'm just going to post an excerpt < c++ primer plus > c++ friend class

Where Remote is the friend class of Tv.

Tv.h


#ifndef TV_H_
#define TV_H_

/*1 A class   TV  */
class Tv
{
public:
  friend class Remote; //Remote Class can be accessed Tv Privite  Private part 
  enum {
    off,on  // switch  
  };
  enum 
  {
    MinVal,MaxVal=20  // The volume 
  };
  enum {
    Antena,Cable // Using an antenna or a cable 
  };
  enum 
  {
    TV ,DVD  // Working mode 
  };

  Tv(int s = off, int mc = 125) :state(s), volume(5), maxchannel(mc),
    channel(5), mode(Cable), input(TV) {}
  void onoff() { state = (state == on) ? off : on; }
  bool ison()const { return state == on; }
  bool volup();  // Increase the voice 
  bool voldown(); // Reduce the sound 
  void chanup(); // channel  +
  void chandown();// channel  -
  void set_mode() { mode = (mode == Antena) ? Cable : Antena; }
  void set_input() { input = (input == TV) ? DVD : TV; }
  void settings()const; // Display all Settings 


private:
  int state;  //  Open or   guan 
  int volume; //  The volume 
  int maxchannel; // The biggest 
  int channel;  // The current channel 
  int mode;  //  Radio or   cable 
  int input; //Tv  or  DVD
};

/*Remote  The definition of   (remote control)  */
class Remote {
private :
  int mode; //  control  TV  or  DVD
public:
  Remote(int m = Tv::TV) :mode(m) {}
  bool volup(Tv & t) { return t.volup(); }
  bool voldown(Tv & t) { return t.voldown(); }
  void onoff(Tv & t) { return t.onoff(); }
  void chanup(Tv & t) { return t.chanup(); }
  void chandown(Tv & t) { return t.chandown(); }
  void set_chan(Tv &t, int c) { t.channel = c; } // Access to the Tv Private member of 
  void set_mode(Tv &t) { t.set_mode(); }
  void set_input(Tv &t) { t.set_input(); }
};
#endif // TV_H_

Tv.cpp


#include "stdafx.h"
#include "Tv.h"
#include <iostream>

bool Tv::volup() {
  if (volume < MaxVal) {
    volume++;
    return true;
  }
  else {
    return false;
  }
}

bool Tv::voldown() {
  if (volume > MinVal) {
    volume--;
    return true;
  }
  else {
    return false;
  }
}

void Tv::chanup() {
  if (channel < maxchannel) channel++;
  else channel = 1;
}

void Tv::chandown() {
  if (channel > 1) channel--;
  else channel = maxchannel;
}

void Tv::settings() const {
  using std::cout;
  using std::endl;
  cout << "TV is " << (state == off ? "off" : "on") << endl;
  if (state == on) {
    cout << "Volume setting =" << volume << endl;
    cout << "Channel setting = " << channel << endl;
    cout << "Mode = " << (mode == Antena ? "antenna" : "cable") << endl;
    cout << "Input = " << (input == TV ? "TV" : "DVD") << endl;
  }
}

Test code:


#include "stdafx.h"
#include "tv.h"
#include <iostream>

int main()
{
  using std::cout;
  Tv s42;
  cout << "Initial settings for 42 \" Tv: \n";
  s42.settings();
  s42.onoff();
  s42.chanup();

  cout << " \n Adjusted settings for 42 \" Tv: \n";
  s42.chanup();
  cout << "\n Adjusted settings for 42 \" Tv: \n";
  s42.settings();

  Remote grey;
  grey.set_chan(s42, 10);
  grey.volup(s42);
  grey.volup(s42);
  cout << " \n s42 \" settings after using remote: \n";
  s42.settings();

  Tv s58(Tv::on);
  s58.set_mode();
  grey.set_chan(s58, 58);
  cout << " \n s58 \" setting: \n";
  s58.settings();

  system("pause");
  return 0;
}

Operation results:


Initial settings for 42 " Tv:
TV is off

 Adjusted settings for 42 " Tv:

 Adjusted settings for 42 " Tv:
TV is on
Volume setting =5
Channel setting = 7
Mode = cable
Input = TV

 s42 " settings after using remote:
TV is on
Volume setting =7
Channel setting = 10
Mode = cable
Input = TV

 s58 " setting:
TV is on
Volume setting =5
Channel setting = 58
Mode = antenna
Input = TV
 Please press any key to continue . . .

The code above sets the Remote class to be a friend of the Tv class, but in fact we can see that the only way a member of Tv can be accessed is by void set_chan(Tv) & t, int c) {t.channel = c; }, so it is the only method that needs a friend. So you don't have to make the whole class a friend, which leads to the friend member function that we're going to talk about next.

2. Friend member function

In Tv, we will set Remote::set_chan() as friendly element:


clas Tv
{
  friend void Remote::set_chan(Tv & t,int c ) ;
}

However, for the compiler to be able to process this statement, it must know the definition of Remote. Otherwise, it cannot know that Remote is a class. set_chan is a method of this class. This means that the definition of Remote should precede the definition of Tv. The Remote method refers to the Tv object, which means that the Tv definition should precede the Remote definition. The way around this loop dependency is to use forward declarations.
So it should look like this:


class Tv ; // Prior to declaration 
class Remote{...}
class Tv {...}

Here's another problem:

Remote contains inline code such as void onoff(Tv) & t) {t.onoff();};

Since this calls one of Tv's methods, the compiler will have seen the Tv class declaration at this point so it knows what Tv's methods are, but as you can see, this declaration follows the Remote declaration. The solution to this problem is to use the Remote declaration to include only method declarations, and put the actual definition behind the Tv class. So it should end up like this:


class Tv; // Prior to declaration 
class Remote {...} // If you want to use Tv  Only method declarations 
class Tv{...}
// Then write Remote The definition of 

You can still call a method inline by using the inline keyword in the method definition
So the program eventually changed tv.h to:


#ifndef TV_H_
#define TV_H_
class Tv; // Prior to declaration 
class Remote {

public:
  enum {
    off, on  // switch  
  };
  enum
  {
    MinVal, MaxVal = 20  // The volume 
  };
  enum {
    Antena, Cable // Using an antenna or a cable 
  };
  enum
  {
    TV, DVD  // Working mode 
  };

private:
  int mode; //  control  TV  or  DVD
public:
  Remote(int m = TV) :mode(m) {}
  // With the help of Tv  Only statements 
  bool volup(Tv & t);
  bool voldown(Tv & t);
  void onoff(Tv & t);
  void chanup(Tv & t);
  void chandown(Tv & t);
  void set_chan(Tv &t, int c);
  void set_mode(Tv &t);
  void set_input(Tv &t);
};

class Tv
{
public:
  friend void Remote::set_chan(Tv & t,int c); // Friend member function 
  enum {
    off, on  // switch  
  };
  enum
  {
    MinVal, MaxVal = 20  // The volume 
  };
  enum {
    Antena, Cable // Using an antenna or a cable 
  };
  enum
  {
    TV, DVD  // Working mode 
  };
  Tv(int s = off, int mc = 125) :state(s), volume(5), maxchannel(mc),
    channel(5), mode(Cable), input(TV) {}
  void onoff() { state = (state == on) ? off : on; }
  bool ison()const { return state == on; }
  bool volup();  // Increase the voice 
  bool voldown(); // Reduce the sound 
  void chanup(); // channel  +
  void chandown();// channel  -
  void set_mode() { mode = (mode == Antena) ? Cable : Antena; }
  void set_input() { input = (input == TV) ? DVD : TV; }
  void settings()const; // Display all Settings 
private:
  int state;  //  Open or   guan 
  int volume; //  The volume 
  int maxchannel; // The biggest 
  int channel;  // The current channel 
  int mode;  //  Radio or   cable 
  int input; //Tv  or  DVD
};

inline bool Remote::volup(Tv & t) { return t.volup(); }
inline bool Remote::voldown(Tv & t) { return t.voldown(); }
inline void Remote::onoff(Tv & t) { return t.onoff(); }
inline void Remote::chanup(Tv & t) { return t.chanup(); }
inline void Remote::chandown(Tv & t) { return t.chandown(); }
inline void Remote::set_chan(Tv &t, int c) { t.channel = c; }
inline void Remote::set_mode(Tv &t) { return t.set_mode(); }
inline void Remote::set_input(Tv &t) { return t.set_input(); }
#endif // TV_H_

The test results remain the same.

* also: you can put an inline function in tv.cpp, but you must remove the inline keyword so that the connectivity of the function becomes external.

3. Other friend relationships

1. The above code indicates that Remote is a friend of Tv. But we also sometimes use two classes that are friends with each other. So Remote is the friend of Tv, and Tv is the friend of Remote

Their definition is similar to the following:


class Remote
class Tv
{
friend clas Remote
public:
  void buzz(Remote & r) ;
  ...
}

class Remote
{
friend class Tv;
public:
  void Bool volup(Tv & t){t.volup();}
  ...
}
inline void Tv::buzz(Remote & r)
{
...
}

Since Remote's declaration follows the Tv declaration, it is possible to define Remote::volup() in the class's definition, but the Tv::buzz() method must be defined outside the Tv declaration so that it is outside the Remote declaration. If you do not want buzz() to be inline, you should define it in a separate method definition file.

2. Mutual friends.

Another situation where you need to use a friend is when a function needs to access private data from two classes. It can be a friend of one class and a friend of another class. Here's an example:


class Analyzer;
class Probe
{
  friend void sync (Analyzer & a,const Probe & p) ;
  friend void sync (Probe & p,const Analyzer & a);
  ...
};
class Analyzer
{
  friend void sync (Analyzer & a,const Probe & p) ;
  friend void sync (Probe & p,const Analyzer & a);
}
inline void sync (Analyzer & a,const Probe & p)
{
  ...
}
inline void sync (Probe & p,const Analyzer & a)
{
  ...
}

If you have any questions, please leave a message or come to the site community to exchange discussion, thank you for reading, hope to help you, thank you for your support of the site!


Related articles: