C++之友元的使用方法

来源:爱站网时间:2022-12-22编辑:网友分享
想要学习C++方面的内容,那就一起跟爱站技术频道小编来掌握下友元的使用方法吧,这里通过实例代码的方式给大家进行了介绍,如果你觉得有需要,一起来看一看吧!

C++中友元的实例详解

尽管友元被授予从外部访问类的私有部分的权限,但他们并不与面向对象的编程思想相悖;相反他提高了公共接口的灵活性。

一、友元类

友元声明可以位于公有、私有活保护部分、其所在位置无关紧要

我直接贴出一个摘自< c++ primer plus >的例子来演示 c++ 友元类

其中 Remote 为 Tv的友元类。

Tv.h

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

#ifndef TV_H_

#define TV_H_

 

/*一个类 电视 */

class Tv

{

public:

  friend class Remote; //Remote类可以访问Tv Privite 的私有部分

  enum {

    off,on  //开关

  };

  enum

  {

    MinVal,MaxVal=20  //音量

  };

  enum {

    Antena,Cable //使用的天线、还是电缆

  };

  enum

  {

    TV ,DVD  //工作模式

  };

 

  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();  //增大声音

  bool voldown(); //减小声音

  void chanup(); //频道 +

  void chandown();//频道 -

  void set_mode() { mode = (mode == Antena) ? Cable : Antena; }

  void set_input() { input = (input == TV) ? DVD : TV; }

  void settings()const; //显示所有设置

 

 

private:

  int state;  // 开或者 关

  int volume; // 音量

  int maxchannel; //最大

  int channel;  //当前频道

  int mode;  // 广播还是 电缆

  int input; //Tv 或者 DVD

};

 

/*Remote 的定义 (遥控器) */

class Remote {

private :

  int mode; // 控制 TV 或 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; } //访问了Tv的私有成员

  void set_mode(Tv &t) { t.set_mode(); }

  void set_input(Tv &t) { t.set_input(); }

};

#endif // TV_H_

Tv.cpp

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

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

  }

}

测试代码:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

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

}

运行结果:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

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

请按任意键继续. . .

上述代码中将Remote类设置成为了Tv类的友元类,但事实上我们看到:唯一访问Tv的成员的方法是void set_chan(Tv &t, int c) { t.channel = c; } ,因此它是唯一需要友元的方法。因此不必让整个类成为友元,这就引出了我们下面要讲的的友元成员函数。

二、友元成员函数

我们要再Tv中将Remote::set_chan()设置成友元:

1

2

3

4

clas Tv

{

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

}

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

1

2

3

class Tv ; //前向声明

class Remote{...}

class Tv {...}

这里还有一个麻烦就是:

Remote 包含了内联代码例如:void onoff(Tv &t) {t.onoff();};

由于这将调用Tv的一个方法,所以编译器此时已经看到了Tv类的声明,这样才能知道Tv有哪些方法,但正如看到的,该声明位于Remote声明的后面。这种问题的解决方法是:使用Remote声明中只包含方法声明,并将实际的定义放到Tv类之后。 所以最终应该这样:

1

2

3

4

class Tv; //前向声明

class Remote {...} //如要用到Tv 只能是方法声明

class Tv{...}

//接着写Remote的定义

这里通过方法定义中使用 inline关键字,仍然可以使方法称为内联方法
所以程序最终将tv.h改为:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83  

#ifndef TV_H_

#define TV_H_

class Tv; //前向声明

class Remote {

 

public:

  enum {

    off, on  //开关

  };

  enum

  {

    MinVal, MaxVal = 20  //音量

  };

  enum {

    Antena, Cable //使用的天线、还是电缆

  };

  enum

  {

    TV, DVD  //工作模式

  };

 

private:

  int mode; // 控制 TV 或 DVD

public:

  Remote(int m = TV) :mode(m) {}

  //用到了Tv 只能是声明

  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); //友元成员函数

  enum {

    off, on  //开关

  };

  enum

  {

    MinVal, MaxVal = 20  //音量

  };

  enum {

    Antena, Cable //使用的天线、还是电缆

  };

  enum

  {

    TV, DVD  //工作模式

  };

  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();  //增大声音

  bool voldown(); //减小声音

  void chanup(); //频道 +

  void chandown();//频道 -

  void set_mode() { mode = (mode == Antena) ? Cable : Antena; }

  void set_input() { input = (input == TV) ? DVD : TV; }

  void settings()const; //显示所有设置

private:

  int state;  // 开或者 关

  int volume; // 音量

  int maxchannel; //最大

  int channel;  //当前频道

  int mode;  // 广播还是 电缆

  int input; //Tv 或者 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_

测试结果不变。

*另外:也可一个将内联函数放在tv.cpp中,但必须去掉inline关键字,这样函数的连接性将成为外部的。

三、其他友元关系

1、上面的代码表示的是Remote是Tv的友元。但我们有时也会用到2个类互相友元。即Remote是Tv的友元,同时 Tv又是Remote的友元

他们定义与下面类似:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15  

16

17

18

19

20

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)

{

...

}

由于Remote的声明位于Tv声明的后面,所以可以在类的定义Remote::volup(),但Tv::buzz()方法必须在Tv声明的外部定义,使其位于Remote声明的外面。如果不希望buzz()是内联的,则应在一个单独的方法定义文件中定义它。

2、共同的友元。

需要使用友元的另一种情况是,函数需要访问两个类的私有数据。它可以是一个类的友元,同时是另一个类的友元。示例如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20  

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)

{

  ...

}

相信小伙伴们看完这篇C++之友元的使用方法详细内容后,对C++的知识点更进一步了,我们每天都会上新一些技术含量高的文章给大家阅读,想要学习就不能错过。

上一篇:C++之汉诺塔实例代码

下一篇:C++中如何调用C函数

您可能感兴趣的文章

相关阅读

热门软件源码

最新软件源码下载