Chapter Fifteen - Friends, Abnormalities

Tomomoto

Classes can not only have friend functions, but also classes can be used as friends. In this case, all methods of the friend class can access the private and protected members of the original class. So although friends are granted access to the private part of the class from the outside, they do not contradict the idea of ​​object-oriented programming, on the contrary, they improve the flexibility of the common interface.

friend class 

Suppose you need to write a simple program that simulates a TV and a remote control, and define two classes Tv and Remote. The remote control can change the state of the TV, which indicates that the Remote class is a friend of the Tv class

First define the Tv class. A TV can be represented by a set of state members (variables that describe various aspects of the TV):

  • switch
  • channel settings
  • volume setting
  • CATV or Antenna Tuning Mode
  • TV coordinator or A/V input 

The following statement makes Remote a friend class:

friend class Remote;

 Friend declarations can be in public, private or protected sections, it doesn't matter where they are located.

tv.h 

#ifndef TV_H_
#define TV_H_

class Tv 
{
public:
	friend class Remote;	//Remote can access Tv private parts
	enum{Off,On};
	enum{MinVal,MaxVal=20};
	enum{Antenna,Cable};
	enum{TV,DVD};

	Tv(int s=Off,int mc=125):state(s),volume(5),maxchannel(mc),channel(2),mode(Cable),input(TV){}
	void onoff() { state = (state == On ? Off : On); }
	bool ison()const { return state == On; }
	bool volup();
	bool voldown();
	void chanup();
	void chandown();
	void set_mode() { mode = (mode == Antenna) ? Cable : Antenna; }
	void set_input() { input = (input == TV) ? DVD : TV; }
	void settings()const;	//display all settings

private:
	int state;	//on or off
	int volume;	//assumed to be digitized
	int maxchannel;	//maximum number of channels
	int channel;	//current channel setting
	int mode;	//broadcast or cable
	int input;	//TV or DVD
};

class Remote
{
private:
	int mode;
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) {  t.onoff(); }
	void chanup(Tv& t) {  t.chanup(); }
	void chandown(Tv& t) { t.chandown(); }
	void set_chan(Tv& t, int c) { t.channel = c; }
	void set_mode(Tv& t) { t.set_mode(); }
	void set_input(Tv& t) { t.set_input(); }

};
#endif // !TV_H_

Except for the constructor, all Remote methods take a Tv object reference as a parameter, which indicates that the remote must be specific to the TV

tv.cpp

#include<iostream>
#include"tv.h"
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 == Antenna ? "antenna" : "cable") << endl;
		cout << "Input = " << (input == TV ? "TV" : "DVD") << endl;
	}
}

use_tv.cpp

#include<iostream>
#include"tv.h"
int main()
{
	using std::cout;
	Tv s42;
	cout << "Initial setting for 42\"TV:\n";
	s42.settings();
	s42.onoff();
	s42.chanup();
	cout << "\nAdjusted setting for 42\"TV:\n";
	s42.settings();

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

	Tv s58(Tv::On);
	s58.set_mode();
	grey.set_chan(s58, 28);
	cout<<"\n58\"setting:\n";
	s58.settings();
	return 0;
}

 

 friend member function

In the code of the previous example, most of the Remote methods are implemented using the public interface of the Tv class. This means that these methods don't really need to be friends. In fact, the only Remote method that directly accesses the Tv member is Remote::set_chan(), so it is the only method that needs to be a friend. You can indeed choose to make only specific class members friends of another class, rather than making the entire class a friend.

But to do so one must be careful about the order of the various declarations and definitions .

The way to make Remote::set_chan() a friend of the Tv class is to declare it as a friend in the Tv class declaration

class Tv
{
	friend void Remote::set_cahn(Tv& t, int c);
	...
};

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 and set_chan is a method of this class. This means that the definition of Remote should be placed before the definition of Tv. The method of Remote mentions the Tv object, which means that the definition of Tv should come before the definition of Remote. The way to avoid this circular dependency is - use forward declaration

class Tv;    //forward declaration
class Remote {...};
class Tv {...};

 RTTI (Runtime Type Identification, runtime type identification)

C++ has 3 elements that support RTTI. (RTTI only applies to classes containing virtual functions)

  • The dynamic_cast operator will use a pointer to the base class to produce a pointer to the derived class if possible; otherwise the operator returns 0 - a null pointer
  • The typeid operator returns a value indicating the type of the object
  • The type_info structure stores information about a particular type 

Guess you like

Origin blog.csdn.net/yangSHU21/article/details/131737467