zoukankan      html  css  js  c++  java
  • 《C++ Primer Plus》15.1 友元 学习笔记

    15.1.1 友元类
    假定需要编写一个模拟电视机和遥控器的简单程序。决定定义一个Tv类和一个Remote类,来分别表示电视机和遥控器。遥控器和电视机之间既不是is-a关系也不是has-a关系。事实上,遥控器可以改变电视机的状态,这表明应将Remote类作为Tv类的一个友元。
    首先定义Tv类:
    友元声明可以位于共有、私有或保护部分,其所在的位置无关紧要。由于Remote类提到了Tv类,所以编译器必须了解Tv类后,才能处理Remote类,为此,最简单的方法是首先定义Tv类。也可以使用前向声明(forward declaration),这将稍候介绍。
    程序清单15.1 tv.h

    // tv.h -- Tv and Remote classes
    #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;           // 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_H_

    程序清单15.3 tv.cpp

    // 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;
        }
        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 << "Inpute = "
                 << (input == TV ? "TV" : "DVD") << endl;
        }
    }

    程序清单15.3是一个简短的程序,可以测试一些特性。灵位,可使用同一个遥控器控制两台不同的电视机。
    程序清单15.3 use_tv.cpp

    // 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
    ";
        s42.settings();
        s42.onoff();
        s42.chanup();
        cout << "
    Adjusted settings for 42" TV:
    ";
        s42.chanup();
        cout << "
    Adjusted settings for 42" TV:
    ";
        s42.settings();
    
        Remote grey;
    
        grey.set_chan(s42, 10);
        grey.volup(s42);
        grey.volup(s42);
        cout << "
    42" settings after using remote:
    ";
        s42.settings();
    
        Tv s58(Tv::On);
        s58.set_mode();
        grey.set_chan(s58, 28);
        cout << "
    58" settings:
    ";
        s58.settings();
        return 0;
    }

    程序输出:

    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 = 4
    Mode = cable
    Inpute = TV
    
    42" settings after using remote:
    TV is On
    Volume setting = 7
    Channel setting = 10
    Mode = cable
    Inpute = TV
    
    58" settings:
    TV is On
    Volume setting = 5
    Channel setting = 28
    Mode = antenna
    Inpute = TV

     15.1.2 友元成员函数
    上一个例子中,唯一直接访问Tv成员的Remote方法是Remote::set_chan(),因此它是唯一需要作为友元的方法。
    让Remoete::set_chan()成为Tv类的友元的方法是,在Tv类声明中将其声明为友元:
    class Tv
    {
        friend void Remote::set_chan(Tv & t, int c);
        ...
    };
    避开“我一来你,你依赖我”的情况出现的方法——使用前向声明(forward declaration)。为此,需要在Remote定义的前面插入下面的语句:
    class Tv;    // forward declaration
    这样,排列次序如下:
    class Tv;    // forward declaration
    class Remote { ... };
    class Tv { ... };
    能否像下面这样排列呢?
    class Remote;
    class Tv { ... };
    class Remote { ... };
    答案是不能。原因在于,在编译器在Tv类的声明中看到Remote的一个方法被声明为Tv类的友元之前,应该先看到Remote类的声明和set_chan()方法的声明。
    ……
    使Remote声明中只包含方法声明,并将实际的定义放在Tv类之后。这样,排列顺序将如下:
    class Tv;        // forward declaration
    class Remote { ... };    // Tv-using methods as prototypes only
    class Tv { ... };
    // put Remote method definitions here

    15.1.4 共同的友元
    需要使用友元的另一种情况是,函数需要访问两个类的私有数据。从逻辑上看,这样的函数应是每个类的成员函数,单这时不可能的。它可以使一个类的成员,同时是另一个类的友元,单有时将函数作为两个类的友元更合理。例如,假定有一个Probe类和一个Analyzer类,前者表示某种可编程的测量设备,后者表示某种可编程的分析设备。这来那个哥类都有内部时钟,且希望它们能够同步,则应该包含下述代码行:
    class Analyzer; // forward declaration
    class Probe
    {
        friend void sync(Analyzer & a, const Probe & p);    // sync a to p
        friend void sync(Prob & 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(Prob & 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是一种类型。

  • 相关阅读:
    Topshelf 搭建 Windows 服务
    Xamarin.Android 6.0以后开启权限方法
    使用ADB安装apk安装包
    C# 杀掉系统中的进程
    C# 使用CefSharp嵌入网站
    .Net Core 基于 SnmpSharpNet 开发
    C#实现ActiveMQ消息队列
    ActiveMQ 安装方法
    C# FluentFTP类上传下载文件
    .NET Core 之 Nancy 基本使用
  • 原文地址:https://www.cnblogs.com/moonlightpoet/p/5669763.html
Copyright © 2011-2022 走看看