天天看點

C++ 友元友元

友元

友元 英文 friend。friend 翻譯成中文就是朋友,翻譯成術語就是:友元。朋友就很好了解了,我的錢你随便花,我的東西你随便用;當然我也是你的朋友,你的錢我随便花,你的東西我随便用。

當然在 C++ 裡,類與類 之間可以作為友元,那麼這個類就可以去操作另外一個類裡面私有的成員;函數與函數 之間也可以作為 友元,是以友元分為: 友元函數 和 友元類。

我們通過一個例子一看就明白了:

寫代碼

#include <iostream>
#include <string>

using namespace std;

class Screen{
public:
    typedef std::string::size_type index;

    Screen(int ht=, int wd=):contents(ht*wd, ' '), cursor(), height(ht), width(wd){}

    int area() const{
        return height * width;
    }
private:
    std::string contents; 
    index cursor;
    int height, width;
};



int main(){
    Screen a;
    cout << a.area() << endl;
    cout << "OK" << endl;

    return ;
}
           

運作現在的程式,程式是可以正常使用的。

現在,我們在

main()

函數的同一級,編寫一個函數,這個函數的功能是:計算螢幕(Screen)的面積。

// 這個函數不是類的成員函數
int calcArea(Screen & screen){
    return screen.height * screen.width;
}
           

如果這個函數像上面這個樣子編寫,程式編譯都通不過。因為

height

width

都是

Screen

類的私有成員。這兩個私有的資料成員隻能在類的内部使用,隻能被類的内部函數使用,因為這個

calcArea()

函數不是類内部的成員函數,是以它是不能使用類内部的私有成員的。

那麼,假如現在,我們把這個

calcArea()

函數變成這個

Screen

類的友元,就是朋友,那麼這個函數就可以使用類裡面私有的成員了。就像是:你是我的朋友,到我家裡來,就像到自己家裡一樣,随便吃随便用随便拿。

現在我們就來定義友元函數。我們将

calcArea()

函數定義成友元函數。

Screen

類裡面,

public

裡面添加下面這句代碼就可以。就這麼簡單:

friend int calcArea(Screen & screen);
           

現在,我們在編譯程式,就沒有錯誤了。運作也沒有問題。

main()

函數裡面寫成下面這個樣子,來測試:

int main(){
    Screen a;
    cout << a.area() << endl;
    cout << calcArea(a) << endl;
    cout << "OK" << endl;
    while(){}
    return ;
}
           

我們也可以将一個類編寫成友元,我們現在來看下面這個例子:(注意: 要将下面的這段代碼放到

Screen

類的下面,否則

Window_Mgr

類找不到

Screen

類。)

// 視窗管理類 - 對Screen類進行管理
class Window_Mgr{
public:
    // 重定位 - 就是改變視窗的height 和 width
    void relocate(int r, int c, Screen& s){
        s.height += r;
        s.width + c;
    }
};
           

因為

Screen

類裡的

height

width

是私有的,不能再

Window_Mgr

類裡面使用的,除非它是友元。

現在編譯程式是報錯的。

我們現在可以将

Window_Mgr

類作為

Screen

類的友元。需要做的事情,隻需要:在

Screen

類裡面的

public

裡面添加下面一句代碼:

friend class Window_Mgr;
           

現在,我們将

Window_Mgr

這個整個類都作為

Screen

類的友元,也就是說:它們現在是朋友,我們家裡的人可以随便到你們家裡面來,你們家裡的人也可以随便到我們家裡面來。

我們在

main()

函數裡面測試一下:

int main(){
    Screen a(, );
    cout << a.area() << endl;

    Window_Mgr w;
    w.relocate(, , a);
    cout << calcArea(a) << endl;

    cout << "OK" << endl;
    while(){}
    return ;
}
           

這就是友元,懂了嗎?

如果我們現在不行讓這個

Window_Mgr

類作為

Screen

類的友元,而是希望隻是

Window_Mgr

類中的一個成員函數是

Screen

類的友元。要如何操作呢?

我們在定義一個類,

Dog

Dog

類裡面就有很多的成員函數。

我現在不想将

Dog

類全部做成

Screen

類的友元,我隻想将

Dog

類裡面的

foo()

共有函數作為

Screen

類的友元,那現在我們要如何去做呢?

很簡單,我們在

Screen

類的

public

裡面添加下面這句代碼就可以:

friend int Dog::foo(Screen & );
           

Q: 現在程式編譯時會通過的,這是為什麼?

A: 有一個問題需要強調一下:友元定義 和 友元聲明 之間有一個依賴。

如果我們将

Dog

類 放在

Screen

類的下面,那麼

Dog

類是可以找到

Screen

類,但是

Screen

類卻找不到

Dog

類裡面的

foo()

函數,因為我們在編寫

foo()

函數的時候,是使用的聲明和定義一體的形式編寫的。

如果我們将

Dog

類 放在

Screen

類的上面, 那麼

Screen

類是可以找到

Dog

類裡面的

foo()

函數,但是

Dog

類現在又找不到

Screen

類了。是以,不管你将

Dog

類放在程式的什麼位置,程式都是沒有辦法編譯通過。要怎樣解決這個問題呢?

我們需要在

Screen

類上面 這樣寫:

class Screen;

class Dog{
public:
    int foo(Screen & screen);

    int koo(Screen & screen){
        return ;
    }
};
           

先對

Screen

類進行聲明,接下定義

Dog

類。并且在

Dog

類裡面 我們将

foo()

函數寫成聲明的形式。這樣就沒有使用到

Screen

類裡面的成員,這樣,程式在編譯這段代碼的時候不需要去找

Screen

的定義。

接着,我們在

Screen

類的下面 這樣寫:

int Dog::foo(Screen & screen){
    return  screen.height * screen.width;
}
           

我們在

Screen

類的下面都

Dog

類裡面的成員函數

foo()

函數進行定義。這樣做的原因是:因為

foo()

成員函數裡面使用到了

Screen

類裡面定義的成員變量,程式在編譯這段函數的代碼的時候,會去上向上找

Screen

類的定義,剛好我們将

foo()

函數的定義寫在

Screen

定義的下面,是以這樣寫就可以用個編譯。

現在在

main()

函數中寫一些測試代碼:

int main(){
    Screen a(, );
    cout << a.area() << endl;

    Dog d;
    cout << d.foo(a) << endl;

    cout << "OK" << endl;
    while(){}
    return ;
}
           

現在 友元 我們就都介紹完畢了。

最後,完整的代碼貼上:

#include <iostream>
#include <string>

using namespace std;

class Screen;

class Dog{
public:
    int foo(Screen & screen);

    int koo(Screen & screen){
        return ;
    }
};


class Screen{
public:
    friend int calcArea(Screen & screen);
    friend class Window_Mgr;
    friend int Dog::foo(Screen & screen);

    typedef std::string::size_type index;

    Screen(int ht=, int wd=):contents(ht*wd, ' '), 
        cursor(), height(ht), width(wd){}

    int area() const{
        return height * width;
    }

private:
    std::string contents; 
    index cursor;
    int height, width;
};

// 視窗管理類 - 對Screen類進行管理
class Window_Mgr{
public:
    // 重定位 - 就是改變視窗的height 和 width
    void relocate(int r, int c, Screen& s){
        s.height += r;
        s.width += c;
    }
};

int Dog::foo(Screen & screen){
    return  screen.height * screen.width;
}


// 這個函數不是類的成員函數
int calcArea(Screen & screen){
    return screen.height * screen.width;
}

int main(){
    Screen a(, );
    cout << a.area() << endl;

    Window_Mgr w;
    w.relocate(, , a);
    cout << calcArea(a) << endl;

    Dog d;
    cout << d.foo(a) << endl;

    cout << "OK" << endl;
    while(){}
    return ;
}
           

總結:

1 . 今天我們學習的就是友元,友元就是找朋友。我們可以将一個函數作為友元,我們也可以将一個類作為友元,也可以将類中的一個成員函數作為友元。

2 . 所有友元函數有兩種: 普通函數 和 類的成員函數(共有 和 私有都可以。)

3 . 友元,道理上是很簡單的。友元了之後,就可以操作所有私有的資料成員和私有函數。

繼續閱讀