欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C++中友元類和嵌套類使用詳解

 更新時(shí)間:2022年08月19日 15:54:27   作者:Shawn-Summer  
友元是一種允許非類成員函數(shù)訪問類的非公有成員的一種機(jī)制??梢园岩粋€(gè)函數(shù)指定為類的友元,也可以把整個(gè)類指定為另一個(gè)類的友元,所謂嵌套類,就是在類中聲明的類。如下代碼中,類Inner就是一個(gè)嵌套類,類Outer是外圍類

前言

友元這個(gè)詞,在學(xué)習(xí)類的時(shí)候肯定接觸過,但是當(dāng)時(shí)我們只用了很多友元函數(shù)。

友元有三種:

  • 友元函數(shù)
  • 友元類
  • 友元類方法

類并非只能擁有友元函數(shù),也可以將類作為友元。在這種情況下,友元類的所以方法都能訪問原始類的私有成員和保護(hù)成員。另外,也可以做更嚴(yán)格的限制,只將特定的成員函數(shù)指定為另一個(gè)類的友元。

1. 友元類

假如我們有兩個(gè)類:Tv電視機(jī)類,Remote遙控器類。那么這兩個(gè)類是什么關(guān)系呢?既不是has-a關(guān)系,也不是 is-a關(guān)系,但是我們知道遙控器可以控制電視機(jī),那么遙控器必須能夠訪問電視機(jī)的私有或保護(hù)數(shù)據(jù)。所以,遙控器就是電視機(jī)的友元。

類似于友元函數(shù)的聲明,友元類的聲明:

friend class Remote;

友元聲明可以位于公有、私有或保護(hù)部分,其所在的位置無關(guān)緊要。

下面是代碼實(shí)現(xiàn):

//友元類1.h
#ifndef TV_H_
#define TV_H_
class Tv
{
private:
    int state;//On or Off
    int volume;//音量
    int maxchannel;//頻道數(shù)
    int channel;//頻道
    int mode;//有線還是天線,Antenna or Cable
    int input;//TV or DVD
public:
    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 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
//友元類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:\study\c++\path_to_c++> g++ -I .\include\ -o 友元類1 .\友元類1.cpp .\友元類1main.cpp
PS D:\study\c++\path_to_c++> .\友元類1.exe
Initial setting for 42" TV:  
Tv is Off

Adjusted settings for 42" TV:
Tv is On
Volume setting = 5
Channel setting = 3
Mode = cable
Input = TV

42" settings after using remote:
Tv is On
Volume setting = 7
Channel setting = 10
Mode = cable
Input = TV

58" settings:
Tv is On
Volume setting = 5
Channel setting = 28
Mode = antenna
Input = TV

總之,友元類和友元函數(shù)很類似,不需要過多說明了。

2. 友元成員函數(shù)

在上面那個(gè)例子中,我們知道大部分Remote方法都是用Tv類的公有接口實(shí)現(xiàn)的。這意味著這些方法不是真正需要作為友元。事實(shí)上,只有一個(gè)直接訪問Tv的私有數(shù)據(jù)的Remote方法即Remote::chan(),因此它才是唯一作為友元的方法。我們可以選擇僅讓特定的類成員成為另一個(gè)類的友元,而不必讓整個(gè)類成為友元,但這樣做會(huì)有一些麻煩。

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聲明的前面。這就發(fā)生了循環(huán)依賴。我們得使用 前向聲明(forward declaration) 來解決這一問題。

class Tv;
class Remote{...};
class Tv{...};

但是,還有一點(diǎn)麻煩需要解決:Remote的類聲明中不能直接給出成員函數(shù)的定義了,因?yàn)檫@些函數(shù)會(huì)訪問Tv類成員,而Tv類的成員的聲明是Remote類的后面的。那么我們必須在Remote的類聲明外給出方法定義。

代碼實(shí)現(xiàn):

//友元成員函數(shù)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 DVD
public:
    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;//頻道數(shù)
    int channel;//頻道
    int mode;//有線還是天線,Antenna or Cable
    int input;//TV or DVD
public:
    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

之前我們說過,內(nèi)聯(lián)函數(shù)的鏈接性是內(nèi)部的,這就意味著函數(shù)定義必須在使用函數(shù)的文件中。在上面的代碼中,內(nèi)聯(lián)函數(shù)的定義位于頭文件中。當(dāng)然你也可以將定義放在實(shí)現(xiàn)文件中,但必須刪除關(guān)鍵字inline,這樣函數(shù)的鏈接性將是外部的。

還有就是,我們直接讓整個(gè)Remote類成為友元并不需要前向聲明,因?yàn)橛言Z句已經(jīng)指出Remote是一個(gè)類:

friend class Remote;。

總之,不推薦使用友元成員函數(shù),使用友元類完全可以達(dá)到相同的目的。

3. 其他友元關(guān)系

3.1 成為彼此的友元類

還是電視機(jī)和遙控器的例子,我們知道遙控器能控制電視機(jī),但是我告訴你,現(xiàn)代電視機(jī)也是可以控制遙控器的。例如,我們現(xiàn)在可以在電視上玩角色扮演游戲,當(dāng)你控制的角色從高處落入水中時(shí),遙控器(手柄)會(huì)發(fā)出振動(dòng)模擬落水感。那么,遙控器是電視機(jī)的友元,電視機(jī)也是遙控器的友元,那么它們互為友元。

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函數(shù)的定義必須放到Remote類聲明的后面,因?yàn)?code>buzz的定義中會(huì)使用到Remote的成員。

3.2 共同的友元

使用友元的另一種情況是,函數(shù)需要訪問兩個(gè)類的私有數(shù)據(jù),那么必須這樣做:函數(shù)既是一個(gè)類的友元也是另一個(gè)類的友元.

例如,有兩個(gè)類AnalyzerProbe,我們需要同步它們的時(shí)間成員:

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++中我們可以將類聲明放在另一個(gè)類中。在另一個(gè)類中聲明的類被稱為嵌套類。

實(shí)際上,嵌套類很簡(jiǎn)單,它的原理和類中聲明結(jié)構(gòu)體、常量、枚舉、typedef、名稱空間是一樣的,這些技術(shù)我們一直都在使用。

對(duì)類進(jìn)行嵌套和包含是不一樣的。包含意味著將類對(duì)象作為另一個(gè)類的成員,而對(duì)類進(jìn)行嵌套不創(chuàng)建類成員,而是定義了一種類型,該類型僅在包含嵌套類的類中有效。

一般來說我們使用嵌套類是為了幫助實(shí)現(xiàn)另一個(gè)類,并避免名稱沖突

嵌套類的作用域和訪問控制

作用域

如果嵌套類是在另一個(gè)類的私有部分聲明的,那么只能在后者的類作用域中使用它,派生類以及外部世界無法使用它。

如果嵌套類是在另一個(gè)類的保護(hù)部分聲明的,那么只能在后者、后者的派生類的類作用域中使用該嵌套類,外部世界無法使用它。

如果嵌套類是在另一個(gè)類的公有部分聲明的,那么能在后者、后者的派生類和外部世界中使用它。

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

上面的Coach就是一個(gè)公有部分的嵌套類,那么我們可以這樣:

Team::Coach forhire;

總之,嵌套類的作用域和類中聲明結(jié)構(gòu)體、常量、枚舉、typedef、名稱空間是一樣。但是對(duì)于枚舉量來說,我們一般把它放在類的公有部分,例如ios_base類中的各種格式常量:ios_base::showpoint等。

訪問控制

嵌套類的訪問控制和常規(guī)類是一模一樣的,嵌套類也有public,private,protected,只有公有部分對(duì)外部世界開放。

例如:

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

則在A的類作用域中,可以創(chuàng)建B對(duì)象,并使用B.foo()方法。

看看一個(gè)類模板中使用嵌套類的例子:

#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){}//搶占定義,賦值構(gòu)造函數(shù)
    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

到此這篇關(guān)于C++中友元類和嵌套類使用詳解的文章就介紹到這了,更多相關(guān)C++友元類和嵌套類內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 深入解析設(shè)計(jì)模式中的適配器模式在C++中的運(yùn)用

    深入解析設(shè)計(jì)模式中的適配器模式在C++中的運(yùn)用

    這篇文章主要介紹了設(shè)計(jì)模式中的適配器模式在C++中的運(yùn)用,通常適配器模式可以細(xì)分為類適配器和對(duì)象適配器兩種情況,需要的朋友可以參考下
    2016-03-03
  • 如何用C寫一個(gè)web服務(wù)器之基礎(chǔ)功能

    如何用C寫一個(gè)web服務(wù)器之基礎(chǔ)功能

    C語言是一門很基礎(chǔ)的語言,程序員們對(duì)它推崇備至,本文將帶著大家來看一下,如何用C寫一個(gè)web服務(wù)器。
    2021-05-05
  • VS中scanf函數(shù)報(bào)錯(cuò)問題的幾種解決方法

    VS中scanf函數(shù)報(bào)錯(cuò)問題的幾種解決方法

    本文主要介紹了VS中scanf函數(shù)報(bào)錯(cuò)問題的幾種解決方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-07-07
  • C++中的const和constexpr詳解

    C++中的const和constexpr詳解

    C++ const 和 constexpr 的區(qū)別呢,constexpr表示這玩意兒在編譯期就可以算出來(前提是為了算出它所依賴的東西也是在編譯期可以算出來的)。而const只保證了運(yùn)行時(shí)不直接被修改(但這個(gè)東西仍然可能是個(gè)動(dòng)態(tài)變量)。下面我們來詳細(xì)講解下。
    2016-01-01
  • Qt利用DOM類實(shí)現(xiàn)讀取xml文件

    Qt利用DOM類實(shí)現(xiàn)讀取xml文件

    Dom(Document Object Model,即文檔對(duì)象模型)能把XML文檔轉(zhuǎn)換成應(yīng)用程序可遍歷的樹形結(jié)構(gòu),這樣便可以隨機(jī)訪問其中的節(jié)點(diǎn)。本文將詳細(xì)講講實(shí)現(xiàn)的方法,需要的可以參考一下
    2022-06-06
  • 結(jié)合C++11新特性來學(xué)習(xí)C++中l(wèi)ambda表達(dá)式的用法

    結(jié)合C++11新特性來學(xué)習(xí)C++中l(wèi)ambda表達(dá)式的用法

    這篇文章主要介紹了C++中l(wèi)ambda表達(dá)式的用法,lambda表達(dá)式的引入可謂是C++11中的一大亮點(diǎn),同時(shí)文中也涉及到了C++14標(biāo)準(zhǔn)中關(guān)于lambda的一些內(nèi)容,需要的朋友可以參考下
    2016-01-01
  • MFC程序執(zhí)行過程深入剖析

    MFC程序執(zhí)行過程深入剖析

    這篇文章主要介紹了MFC程序執(zhí)行過程,包括對(duì)MFC執(zhí)行流程的分析以及斷點(diǎn)調(diào)試分析出的SDI程序執(zhí)行流程,需要的朋友可以參考下
    2014-09-09
  • 簡(jiǎn)單總結(jié)C++中的修飾符類型

    簡(jiǎn)單總結(jié)C++中的修飾符類型

    這篇文章主要介紹了C++中的修飾符類型總結(jié),是C++入門學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下
    2016-05-05
  • C語言中函數(shù)聲明與調(diào)用問題

    C語言中函數(shù)聲明與調(diào)用問題

    以下是對(duì)C語言中的函數(shù)聲明與調(diào)用進(jìn)行了詳細(xì)的分析介紹,需要的朋友可以過來參考下
    2013-08-08
  • C++?string如何獲取文件路徑文件名、文件路徑、文件后綴(兩種方式)

    C++?string如何獲取文件路徑文件名、文件路徑、文件后綴(兩種方式)

    這篇文章主要介紹了C++?string如何獲取文件路徑文件名、文件路徑、文件后綴(兩種方式),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。
    2023-06-06

最新評(píng)論