中友元类和嵌套类如何使用

湘潭网餐饮知识
233

湘潭网小编为大家带来以下内容:

今天小编给大家分享一下C++中友元类和嵌套类如何使用的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。前言

友元这个词,在学习类的时候肯定接触过,但是当时我们只用了很多友元函数。

友元有三种:

友元函数

友元类

友元类方法

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

1. 友元类

假如我们有两个类:Tv电视机类,Remote遥控器类。那么这两个类是什么关系呢?既不是has-a关系,也不是 is-a关系,但是我们知道遥控器可以控制电视机,那么遥控器必须能够访问电视机的私有或保护数据。所以,遥控器就是电视机的友元。

类似于友元函数的声明,友元类的声明:

friend class Remote;

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

下面是代码实现:

//友元类1.h#ifndef TV_H_#define TV_H_class Tv{private:    int state;//On or Off    int volume;//音量    int maxchannel;//频道数    int channel;//频道    int mode;//有线还是天线,Antenna or Cable    int input;//TV or DVDpublic:    friend class Remote;    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;//控制TV or DVDpublic:    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//友元类1.cpp#include"友元类1.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==Antenna?"antenna":"cable")<<endl;        cout<<"Input = "            <<(input==TV?"TV":"DVD")<<endl;    }}//友元类1main.cpp#include<iostream>#include"友元类1.h"int main(){    using std::cout;    Tv s42;    cout<<"Initial setting 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;}

PS D:studyc++path_to_c++> g++ -I .include -o 友元类1 .友元类1.cpp .友元类1main.cppPS D:studyc++path_to_c++> .友元类1.exeInitial setting for 42" TV:  Tv is Off

Adjusted settings for 42" TV:Tv is onVolume setting = 5Channel setting = 3Mode = cableInput = TV

42" settings after using remote:Tv is onVolume setting = 7Channel setting = 10Mode = cableInput = TV

58" settings:Tv is onVolume setting = 5Channel setting = 28Mode = antennaInput = TV

总之,友元类和友元函数很类似,不需要过多说明了。

2. 友元成员函数

在上面那个例子中,我们知道大部分Remote方法都是用Tv类的公有接口实现的。这意味着这些方法不是真正需要作为友元。事实上,只有一个直接访问Tv的私有数据的Remote方法即Remote::chan(),因此它才是唯一作为友元的方法。我们可以选择仅让特定的类成员成为另一个类的友元,而不必让整个类成为友元,但这样做会有一些麻烦。

让Remote::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;class Remote{...};class Tv{...};

但是,还有一点麻烦需要解决:Remote的类声明中不能直接给出成员函数的定义了,因为这些函数会访问Tv类成员,而Tv类的成员的声明是Remote类的后面的。那么我们必须在Remote的类声明外给出方法定义。

代码实现:

//友元成员函数1.h#ifndef TVFM_H_#define TVFM_H_class Tv;class Remote{public:    enum{Off,On};    enum{MinVal,MaxVal=20};    enum{Antenna,Cable};    enum{TV,DVD};private:    int mode;//控制TV or DVDpublic:    Remote(int m=TV):mode(m){};    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{private:    int state;//On or Off    int volume;//音量    int maxchannel;//频道数    int channel;//频道    int mode;//有线还是天线,Antenna or Cable    int input;//TV or DVDpublic:    friend void Remote::set_chan(Tv &t,int c);    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};inline bool Remote::volup(Tv & t){return t.volup();}inline bool Remote::voldown(Tv & t){return t.voldown();}inline void Remote::onoff(Tv &t){t.onoff();}inline void Remote::chanup(Tv &t){t.chanup();}inline void Remote::chandown(Tv &t){t.chandown();}inline void Remote::set_chan(Tv &t,int c){t.channel=c;}inline void Remote::set_mode(Tv &t){t.set_mode();}inline void Remote::set_input(Tv &t){t.set_input();}#endif

之前我们说过,内联函数的链接性是内部的,这就意味著函数定义必须在使用函数的文件中。在上面的代码中,内联函数的定义位于头文件中。当然你也可以将定义放在实现文件中,但必须删除关键字inline,这样函数的链接性将是外部的。

还有就是,我们直接让整个Remote类成为友元并不需要前向声明,因为友元语句已经指出Remote是一个类:

friend class Remote;。

总之,不推荐使用友元成员函数,使用友元类完全可以达到相同的目的。

3. 其他友元关系3.1 成为彼此的友元类

还是电视机和遥控器的例子,我们知道遥控器能控制电视机,但是我告诉你,现代电视机也是可以控制遥控器的。例如,我们现在可以在电视上玩角色扮演游戏,当你控制的角色从高处落入水中时,遥控器(手柄)会发出振动模拟落水感。那么,遥控器是电视机的友元,电视机也是遥控器的友元,那么它们互为友元。

class Tv{friend class 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){    ...}

这里buzz函数的定义必须放到Remote类声明的后面,因为buzz的定义中会使用到Remote的成员。

3.2 共同的友元

使用友元的另一种情况是,函数需要访问两个类的私有数据,那么必须这样做:函数既是一个类的友元也是另一个类的友元.

例如,有两个类Analyzer和Probe,我们需要同步它们的时间成员:

class Analyzer;class Probe{    friend void sync(Analyzer & a,const Probe &p);    friend void sync(Probe &p,const Analyzer &a);};class Probe{    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){    ...}4. 嵌套类

在C++中我们可以将类声明放在另一个类中。在另一个类中声明的类被称为嵌套类。

实际上,嵌套类很简单,它的原理和类中声明结构体、常量、枚举、typedef、名称空间是一样的,这些技术我们一直都在使用。

对类进行嵌套和包含是不一样的。包含意味著将类对象作为另一个类的成员,而对类进行嵌套不创建类成员,而是定义了一种类型,该类型仅在包含嵌套类的类中有效。

一般来说我们使用嵌套类是为了帮助实现另一个类,并避免名称冲突

嵌套类的作用域和访问控制作用域

如果嵌套类是在另一个类的私有部分声明的,那么只能在后者的类作用域中使用它,派生类以及外部世界无法使用它。

如果嵌套类是在另一个类的保护部分声明的,那么只能在后者、后者的派生类的类作用域中使用该嵌套类,外部世界无法使用它。

如果嵌套类是在另一个类的公有部分声明的,那么能在后者、后者的派生类和外部世界中使用它。

class Team{public:    class Coach{...}    ...};

上面的Coach就是一个公有部分的嵌套类,那么我们可以这样:

Team::Coach forhire;

总之,嵌套类的作用域和类中声明结构体、常量、枚举、typedef、名称空间是一样。但是对于枚举量来说,我们一般把它放在类的公有部分,例如ios_base类中的各种格式常量:ios_base::showpoint等。

访问控制

嵌套类的访问控制和常规类是一模一样的,嵌套类也有public,private,protected,只有公有部分对外部世界开放。

例如:

class A{    class B    {    private:        int num;    public         void foo();    };};

则在A的类作用域中,可以创建B对象,并使用B.foo()方法。

看看一个类模板中使用嵌套类的例子:

#ifndef QUEUETP_H_#define QUEUETP_H_template<typename Item>class QueueTP{private:    enum{Q_SIZE=10};    class Node    {    public:        Item item;        Node *next;        Node(const Item & i):item(i),next(0){}    };    Node *front;    Node *rear;    int items;    const int qsize;    QueueTP(const QueueTP &q):qsize(0){}//抢占定义,赋值构造函数    QueueTP & operator=(const QueueTP &q){return *this;}//抢占定义public:    QueueTP(int qs=Q_SIZE):qsize(qs)    {        front = rear =0;        items=0;    }    ~QueueTP()    {        Node* temp;        while (front !=0)        {            temp=front;            front=front->next;            delete temp;        }    }    bool isempty() const    {        return items==0;    }    bool isfull() const    {        return items==qsize;    }    int queuecount() const    {        return items;    }    bool enqueue(const Item & item)    {        if(isfull())            return false;        Node * add = new Node(item);        items++;        if(front==0)            front=add;        else            rear->next=add;        rear=add;        return true;    }    bool dequeue(Item &item)    {        if(front==0)            return 0;        item=front->item;        items--;        Node * temp=front;        front=front->next;        delete temp;        if(items==0)            rear=0;        return true;    }};#endif

以上就是“C++中友元类和嵌套类如何使用”这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获,小编每天都会为大家更新不同的知识,如果还想学习更多的知识,请关注花开半夏行业资讯频道。

君子莲(www.junzilian.com)湖南省长沙、株洲、湘潭城市宣传信息网,提供房产,人才招聘,家居装饰,教育,论坛,旅游,特产,美食,天气,娱乐,企业等资讯。



最新餐饮知识

热门推荐

为你推荐