zoukankan      html  css  js  c++  java
  • C++_友元2-友元成员函数

    接着上一篇《友元是什么》中,我们发现Remote友元类的大多数方法都是用Tv类的公有接口实现。这意味着这些方法并不是真正需要友元。

    事实上唯一直接访问Tv成员的Remote方法是Remote::set_chan(),因此它是唯一需要作为友元的方法。

    确实可以仅让特定的类成员成为另一类的友元。

    这种做法稍微有点麻烦,必须小心排列各种声明和定义的顺序。

     

    让Remote::set_chan()成为Tv类的友元的方法是,在Tv类声明中将其声明为友元:

     class Tv

    {

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

    }

    要让编译器能够处理这条语句,它必须知道Remote的定义。否则,它无法知道Remote是一个类,而set_chan是一个类方法;

    这就意味着要把Remote的定义放到Tv类定义之前。

    但是Remote方法提到了Tv对象,而这就意味着Tv定义应当放在Remote定义之前。

    这就产生了循环依赖的问题。要避免循环依赖关系,就要使用前向声明(forward declaration)

    解决方法如下:

    class Tv;  //forward declaration  告诉编译器Tv是一个类

    class Remote {...};  //然后再Remote中出现set_chan 方法时,知道其中Tv是一个类

    class Tv {...};

    //这里补充一句,让整个Remote类成为友元并不需要前向声明,因为友元语句本身已经指出Remote是一个类;

    friend class Remote;

    但是能否像下面这样排列呢?

    class Remote ;  //forward declaration

    class Tv {...};

    class Remote {...};

    答案是不能,因为在编译器看到Tv类的声明中看到Remote的一个方法被声明为Tv类的友元之前,应先看到Remote类的声明和set_chan()方法的声明。

    还有一个麻烦就是。Remote声明中包含了内联代码

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

    由于这将调用Tv的一个方法,所以编译器此时必须已经看到了Tv类的声明。这样才能知道Tv有哪些方法,但正如看到的,该声明位于Remote声明的后面。

    这种问题的解决方法是,使Remote声明中只包含方法声明,并将实际的定义放在Tv类之后。

    class Tv;  //forward declaration

    class Remote {...};  //Tv-using methods as prototypes only  只包含方法的声明

    class Tv {...};

    //put Remote method definitions here  定义在这里写

    Remote方法的声明与下面类似

    void onoff(Tv & t);

    检查该原型时,编译器都需要知道Tv是一个类,而向前声明提供了这样的信息。

    当编译器到达真正的方法定义时,它已经读取到了Tv类的声明,并拥有编译这些方法的所需信息。

    通过在方法定义中使用inline关键字,仍然可以使其成为内联方法。

    //这种友元成员函数的声明、定义顺序非常微妙,令人抓狂。很容易造成错误,一旦问题复杂起来,定位bug都很困难。难怪C++是个大坑。友元的存在就是其中一个大坑。把类的关系,函数的关系搞复杂了。

    tvfm.h

     1 #ifndef TVFM_H_
     2 #define TVFM_H_
     3 
     4 class Tv;  //forward declaration
     5 
     6 class Remote
     7 {
     8 public:
     9     enum State{Off,On};
    10     enum {MinVal, Maxval=20};
    11     enum {Antenna, Cable};
    12     enum {TV, DVD};
    13     
    14 private:
    15     int mode;
    16     
    17 public:
    18     Remote(int m = TV):mode(m) {}
    19     bool volup(Tv & t);
    20     bool voldown(Tv & t);
    21     bool onoff(Tv & t);
    22     bool chanup(Tv & t);
    23     bool chandown(Tv & t);
    24     void set_mode(Tv & t);
    25     void set_input(Tv & t);
    26     void set_chan(Tv & t, int c);
    27 };
    28 
    29 class Tv
    30 {
    31 public:
    32     friend void Remote::set_chan(Tv & t, int c);
    33     enum State{Off, On};
    34     enum {Minval, Maxval =20};
    35     enum {Antenna, Cable};
    36     enum {Tv, DVD};
    37     
    38     Tv(int s=Off, int mc=125):state(s),volume(5),maxchannel(mc),channel(2),mode(Cable),input(TV) {}
    39     void onoff() {state = (state==On)?Off:On;}
    40     bool ison() const {return state == On;}
    41     bool volup();
    42     bool voldown();
    43     void chanup();
    44     void chandown();
    45     void set_mode() {mode = (mode == Antenna)?Cable:Antenna;}
    46     void set_input() {input = (input == TV)?DVD:TV;}
    47     void settings() const;
    48     
    49 private:
    50     int state;
    51     int volume;
    52     int channel;
    53     int maxchannel;
    54     int mode;
    55     int input;
    56 };
    57 
    58 //Remote methods as inline functions
    59 inline bool Remote::volup(Tv & t) {return t.volup();}
    60 inline bool Remote::voldown(Tv & t) {return t.voldown();}
    61 inline void Remote::onoff(Tv & t) {t.onoff();}
    62 inline void Remote::chanup(Tv & t) {t.chanup();}
    63 inline void Remote::chandown(Tv & t) {t.chandown();}
    64 inline void Remote::set_mode(Tv & t) {t.set_mode();}
    65 inline void Remote::set_input(Tv & t) {t.set_input();}
    66 inline void Remote::set_chan(Tv & t, int c) {t.channel = c;}
  • 相关阅读:
    django QuerySet对象转换成字典对象
    HTTP请求中三种参数类型
    django开发中遇到的问题
    win7下mysql8.0.12解压缩版安装
    Django小部件
    程序员上班有什么提高效率的技巧?
    Android应用AsyncTask处理机制详解及源码分析
    Android常用工具类
    Android Volley解析
    Android 开发有哪些新技术出现?
  • 原文地址:https://www.cnblogs.com/grooovvve/p/10421190.html
Copyright © 2011-2022 走看看