C++:友元

C++:友元

标签(空格分隔): c++


类并非只能拥有友元函数,也可以将类作为友元。在这种情况下,友元类的所有方法都可以访问原始类的私有成员和保护成员。另外,也可以做更严格的限制,只有将特定成员函数指定为另一个类的友元。1

友元类


这里我们以遥控器与电视机的关系为例,电视机与遥控器有关系,但是其关系不是继承的is-a关系,同样也不可能是包含has-a关系。所以这里提出了一种新的联系方式:友元类

现在我们设计一款电视,这个电视不保留除开机键外的一切按键,所有一切都由遥控器控制,也就是要求遥控器能够访问电视的私有成员,遥控器又作为电视机的用户接口。

#ifndef primer_tv_h
#define primer_tv_h
#include<iostream>
class Tv{
private:
    enum {LESS=0,LARGE=100,CHANNEL=64};//音量范围0-100,频道数量255
    bool _power;//电源接通状态
    bool _switch;//待机切换状态
    int _voice;//声音
    int _channel;//频道
    void switch_(){
        if(_power){//只有电源接通状况下才可以切换待机状态
            _switch = !_switch;
            if(_switch) show();
        }
    }
    void voiceUp(){
        if(_switch){//调大音量
            if(_voice < LARGE) _voice++;
            show();
        }
    }
    void voiceDown(){
        if(_switch){//调小音量
            if(_voice > LESS) _voice--;
            show();
        }
    }
    void channelPiror(){
        if(_switch){//向前换台
            _channel = (_channel-1)%LARGE;
            show();
        }
    }
    void channelNext(){
        if(_switch){//向后换台
            _channel = (_channel+1)%LARGE;
            show();
        }
    }
    void channel(int c){//切换到某一频道
        if(c<0)
            _channel = 0;
        else if(c>CHANNEL)
            _channel = CHANNEL;
        else
            _channel = c;
        show();
    }
    void show(){//显示节目状态
        std::cout<<"~~~当前电视频道:"<<_channel<<" ,电视音量:"<<_voice<<"~~~"<<endl;
    }

public:
    friend class Remote;//声明友元遥控器
    Tv(){
        _power = false;
        _switch = false;
        _voice = 20;
        _channel = 0;
    }
    ~Tv(){}
    void powerOn(){
        _power = true;
    }
    void powerOff(){
        _switch = false;
        _power = false;
    }
};

class Remote{
private:
    Tv *_tv;
public:
    Remote(Tv *tv):_tv(tv){};
    ~Remote(){}
    void switch_(){_tv->switch_();}
    void voiceUp(){_tv->voiceUp();}
    void voiceDown(){_tv->voiceDown();}
    void channelPiror(){_tv->channelPiror();}
    void channelNext(){_tv->channelNext();}
    void channel(int c){_tv->channel(c);}
};

#endif

现在我们来测试一下

#include"stdafx.h"
#include "tv.h"

int main(int argc, const char * argv[]) {
    cout<<"买了一个小米的新电视"<<endl;
    Tv *mi = new Tv();
    cout<<"打开箱子一看发现了一台遥控器"<<endl;
    Remote mi_r(mi);
    cout<<"我想看电视于是使用遥控器打开开关"<<endl;
    mi_r.switch_();
    cout<<"发现电视并没有什么反应,仔细检查后发现一激动忘记接电源了,"<<"现在接通电源"<<endl;
    mi->powerOn();
    cout<<"再用遥控器打开"<<endl;
    mi_r.switch_();
    cout<<"果然看到节目了,累了一天打算看新闻联播放松放松,由于知道13频道是新闻频道,所以直接在遥控器上输入13"<<endl;
    mi_r.channel(133);
    cout<<"为什么是64频道,仔细一看是自己多按了一个3,于是自己小心的又按了一遍13"<<endl;
    mi_r.channel(13);
    cout<<"啊,看到新闻联播后突然很困,就想把声音关小一点"<<endl
        <<"然后我就一直一直按减小音量键"<<endl;
    for(int i=0;i<30;i++){
        mi_r.voiceDown();
    }
    cout<<"看来我确实是太困了,都按了这么多下按键,算了待机睡觉吧"<<endl;
    mi_r.switch_();
    cout<<"我看看待机后按键有没有用"<<endl;
    mi_r.channelPiror();
    mi_r.channelNext();
    mi_r.voiceDown();
    cout<<"按了三个按键都没反应,看来真待机了,为了省电我要关闭电源键"<<endl;
    mi->powerOff();
    cout<<"可以安心睡觉了"<<endl;
    return 0;
}

从这个例子中我们可以看出,友元声明可以位于公有、私有或者保护部分,其所在的位置无关紧要。由于我们在Remote类中使用Tv类,所以必须在Remote类前声明class Tv

友元成员函数


假如我们现在有一台老式的电视,这台电视提供了许多公有的按键。于是我们的遥控器访问这些方法的时候并不需要真正的友元,唯一需要成为友元方法的是channel方法,因为电视机上不可能会给你提供数字按键

class Tv{
private:
    ...
    void channel(int c);//切换到某一频道
    void show();//显示节目状态
public:
    ...
    void voiceUp();
    void voiceDown();
    void channelPiror();
    void channelNext();
};

那么我们仅仅需要让Remote.channel(int c)的方法成为Tv的友元:

class Tv{
    ...
    friend void Remote::channel(int c);
};

然而,要使编译器能够处理这条指令,它必须知道Remote的定义:

class Remote;
class Tv{
    ...
    friend void Remote::channel(int c);
};

共同的友元


最简单的例子,我们的遥控器不仅仅只能控制一台电视机的。所以我们可以给两台Tv声明同一个遥控器作为友元类。


  1. Stephen Prata.C++ Primer Plus 6th.人民邮电出版社.2015.3 602-611
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值