❥关于C++之友元类

Posted itzyjr

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了❥关于C++之友元类相关的知识,希望对你有一定的参考价值。

友元类的所有方法都可以访问原始类的私有成员和保护成员。

看一个电视与遥控器的示例。遥控器可以改变电视机的状态,这表明应将Romote类作为Tv类的一个友元。

// tv.h -- Tv and Remote classes
#ifndef TV_H_
#define TV_H_
class Tv 
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
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
;
 
class Remote 
private:
    int mode;              // controls 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)  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.cpp -- methods for the Tv class (Remote methods are inline)
#include <iostream>
#include "tv.h"
bool Tv::volup() 
	if (volume < MaxVal) 
		volume++;
		return true;
	
	return false;

bool Tv::voldown() 
	if (volume > MinVal) 
		volume--;
		return true;
	
	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 -- using the Tv and Remote classes
#include <iostream>
#include "tv.h"
int main() 
    using std::cout;
    Tv s42;
    cout << "Initial settings for 42\\" TV:\\n";
    s42.settings();
    s42.onoff();
    s42.chanup();
    cout << "\\nAdjusted settings for 42\\" TV:\\n";
    s42.settings();
 
    Remote grey;
 
    grey.set_chan(s42, 10);
    grey.volup(s42);
    grey.volup(s42);
    cout << "\\n42\\" settings after using remote:\\n";
    s42.settings();
 
    Tv s58(Tv::On);
    s58.set_mode();
    grey.set_chan(s58,28);
    cout << "\\n58\\" settings:\\n";
    s58.settings();
    return 0; 
Initial settings for 42" TV:
TV is Off

Adjusted settings for 42" TV:
TV is On
Volume setting = 5
Channel setting = 3
Mode = cable
Input = TV

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

58" settings:
TV is On
Volume setting = 5
Channel setting = 28
Mode = antenna
Input = TV

关键点:友元类的所有方法都可以访问原始类的私有成员和保护成员。只需在原始类中加上一句声明:friend class Remote; 即让Remote类成为原始类的友元类。

如果想让只有特定的Remote方法是Tv类的友元呢?

假设只让Remote类的set_chan方法成为Tv类的友元,只需将友元类声明那行替换为:

class Tv 
public:
    friend void Remote::set_chan(Tv& t, int c);// 替换friend class Remote;
    ...

区别在于,只有一个Remote方法(称之为友元成员函数)是Tv类的友元,而在原来的版本中,所有的Remote方法都是Tv类的友元。

对于友元成员函数,存在个问题,如下:(对于友元类不存在这个问题)

前向声明与正确的排列顺序:

要使编译器能够处理这条语句,它必须知道Remote的定义。否则,它无法知道Remote是一个类,而set_chan是这个类的方法。这意味着应将Remote的定义放到Tv的定义前面。Remote的方法提到了Tv对象,而这意味着Tv定义应当位于Remote定义之前。避开这种循环依赖的方法是,使用前向声明(forward declaration)。为此,需要在Remote定义的前面插入下面的语句:

class Tv;// forward declaration
正确的排列:
class Tv; ←前向声明
class Remote void set_chan(Tv & t, int c) t.channel = c;...;
class Tv friend void Remote::set_chan(Tv& t, int c);...;
————————————————————————
不能像下面这样排列:
class Remote; ←前向声明
class Tv friend void Remote::set_chan(Tv& t, int c);...;
class Remote void set_chan(Tv & t, int c) t.channel = c;...;

不能用以上的第二种排列方式,原因在于:在编译器在Tv类的声明中看到Remote的一个方法被声明为Tv类的友元之前,应该先看到Remote类的声明和set_chan方法的声明。

对于友元成员函数参数中用到原始类类型的情况,正确的排列顺序就是:

原始类的前向声明->友元类定义->原始类定义

共同的友元函数: 

所谓“共同”就是:友元函数是一个类的成员,同时也是另一个类的成员。

例如,假定有一个Probe类和一个Analyzer类,前者表示某种可编程的测量设备,后者表示某种可编程的分析设备。这两个类都有内部时钟,且希望它们能够同步,则应该包含下述代码行:

class Analyzer; ←前向声明
class Probe 
    friend void sync(Analyzer& a, const Probe& p);// sync a to p
    friend void sync(Probe& p, const Analyzer& a);// sync p to a
    ...
;
class Analyzer 
    friend void sync(Analyzer& a, const Probe& p);// sync a to p
    friend void sync(Probe& p, const Analyzer& a);// sync p to a
    ...
;
// define the friend functions
inline void sync(Analyzer& a, const Probe& p) ...
inline void sync(Probe& p, const Analyzer& a) ...

前向声明使编译器看到Probe类声明中的友元声明时,知道Analyzer是一种类型。

以上是关于❥关于C++之友元类的主要内容,如果未能解决你的问题,请参考以下文章

类和对象之友元

C++学习之友元整理总结

C++之友元函数的使用

C++之友元函数的使用

C++之:友元类

C++友元类