溫習C++友元

友元函數和友元類

類的友元函數是定義在類外部,但有權訪問類的所有私有(private)成員和保護(protected)成員。儘管友元函數的原型有在類的定義中出現過,但是友元函數並不是成員函數。

友元可以是一個函數,該函數被稱爲友元函數;友元也可以是一個類,該類被稱爲友元類,在這種情況下,整個類及其所有成員都是友元。
爲什麼要使用友元函數
運算符重載的某些場合需要使用友元。(略)
兩個類要共享數據:允許外面的類或函數去訪問類的私有變量和保護變量,從而使兩個類共享同一函數。

友元函數的優缺點
優點:方便
缺點:友元函數破環了封裝機制。不得已的情況下才使用友元函數

友元函數

class A
{
public:
    A(int _a):a(_a){};
    A() = default;
    friend int getA_a(A &_classA);//友元函數
    friend std::ostream& operator <<(std::ostream &os,const A& a);
    friend std::istream& operator >>(std::istream &in,A& a);
    int getA_a(){
        std::cout <<"調用類成員函數"<< std::endl;
        return this->a;
    }
private:
    int a;
};

int getA_a(A &_classA){
    std::cout <<"調用友元函數"<< std::endl;
    return _classA.a;//通過對象名訪問私有變量
}
std::ostream& operator <<(std::ostream &os,const A& a){
    os << a.a;
    return os;
}
std::istream& operator >>(std::istream& in,A& a){
    in >> a.a;
    return in;
}

友元類

// 友元類主要爲了提高效率,同時避免public 過於開放
class C;
class B{
public:
    B(int _b):b(_b){}
    void set(int v){
        b += v / 3 + v / 4;
    }
    friend class C;
    void set_c(std::shared_ptr<C> c){
        c_ptrl = c;
    }
private:
    int b;
    std::shared_ptr<class C> c_ptrl;
};
class C{
public:
    void set_c(B b){
        this->c = 2 * get_b(b);
    }
    void get_bc(B b){
        std::cout <<get_b(b) <<"   "<<this->c<< std::endl;
    }
private:
    int c;
    int get_b(B b){
        return b.b;
    }
};

測試

int main(int argc, char* argv[])
{
	// test friend function
    A _classA(3);
    std::cout << getA_a(_classA)<<std::endl;;//友元函數只是普通函數,可以在任意地方調用
    std::cout << _classA.getA_a() << std::endl;
    A a;
    std::cin >> a;
    std::cout << a << std::endl;
    
    // test friend class
    B b{0};
    std::shared_ptr<C> c(new C{});
    b.set_c(c);
    using namespace std::chrono_literals;
    auto RUN_B = [](B *b){
        for(int i = 0; i < 10000; i++){
            b->set(i);
            std::this_thread::sleep_for(10ms);
        }
    };
    std::thread t1(RUN_B,&b);
    auto RUN_C = [](std::shared_ptr<C> c,B &b){
        int i = 0;
        while(true){
            c->set_c(b);
            std::cout <<i++<<"  :  ";c->get_bc(b);
            std::this_thread::sleep_for(1s);
        }
    };
    std::thread t2(RUN_C,c,std::ref(b));
    t1.join();
    t2.join();
    return 0;
}

因爲友元函數沒有this指針,則參數要有三種情況:

要訪問非static成員時,需要對象做參數
要訪問static成員或全局變量時,則不需要對象做參數
如果做參數的對象是全局對象,則不需要對象做參數
友元函數的位置
因爲友元函數是類外的函數,所以它的聲明可以放在類的私有段或公有段且沒有區別。

友元函數的調用
直接調用,不需要通過對象或指針

友元類個人認爲主要在結合Pimp使用

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章