1,友元函數的定義和作用
我們已知道類具有封裝和資訊隐藏的特性。隻有類的成員函數才能通路類的私有成員,程式中的其他函數是無法通路私有成員的。非成員函數可以通路類中的公有成員,但是如果将資料成員都定義為公有的,這又破壞了隐藏的特性。另外,應該看到在某些情況下,特别是在對某些成員函數多次調用時,由于參數傳遞,類型檢查和安全性檢查等都需要時間開銷,而影響程式的運作效率。
為了解決上述問題,提出一種使用友元的方案。友元是一種定義在類外部的普通函數,但它需要在類體内進行說明,為了與該類的成員函數加以差別,在說明時前面加以關鍵字friend。友元不是成員函數,但是它可以通路類中的私有成員。友元的作用在于提高程式的運作效率(即減少了類型檢查和安全性檢查等都需要的時間開銷),但是,它破壞了類的封裝性和隐藏性,使得非成員函數可以通路類的私有成員。
2,上述的通路不是直接通路,對于普通私有成員變量是通過對象通路,對于私有靜态變量是通過類通路。
為什麼不能直接通路呢?
先了解一下為什麼成員函數可以直接通路成員變量?
成員函數能夠通路類的成員變量是因為傳遞了指向目前對象的this指針,它如果通路資料成員對其操作是this指向的對象的資料成員,是有實際意義的 。
友元函數不是成員函數,沒有傳遞隐藏的this指針,隻能間接通路。
這點其實和靜态成員函數一樣,靜态成員函數也是沒有this指針的,是以它隻能通路靜态成員變量或者通過對象通路非靜态成員變量。
例子:
class Rect
{
public:
Rect() // 構造函數,計數器加1
{
count++;
}
//Rect(const Rect& r)
//{
// width = r.width;
// height = r.height;
// count++;
//}
~Rect() // 析構函數,計數器減1
{
count--;
}
static int getCount() // 傳回計數器的值
{
return count;
}
friend int get();
private:
int width;
int height;
static int count; // 一靜态成員做為計數器
};
int Rect::count = 0; // 初始化計數器
int get()
{
return Rect::count;//友元函數通過類通路私有靜态成員變量
}
int main()
{
Rect rect1;
cout<<"The count of Rect: "<<Rect::getCount()<<endl;//通過類通路公有靜态成員函數,輸出1
Rect rect2(rect1); // 使用rect1複制rect2,此時應該有兩個對象
cout<<"The count of Rect: "<<Rect::getCount()<<endl; //輸出1
cout << get() << endl;//輸出1
//cout << Rect::count << endl;//不能編譯通過,不能通路私有成員
system("pause");
return 0;
}
3,類和類之間的友元關系不能繼承。
下邊轉載自:
http://blog.csdn.net/shandianling/article/details/7469361
C++ Primer中有如下描述:友元關系不能繼承。基類的友元對派生類的成員沒有特殊通路
權限。如果基類被授予友元關系,則隻有基類具有特殊通路權限,該基類的派生類不能通路授予友元關系的類。
然而通過實踐發現,VS編譯器并沒有安裝上述描述來處理,下面的規則與上述描述相悖,卻符合VS編譯器的處理規則。
注:有待通過g++編譯器來驗證。
1 友元類的繼承問題
1.1 A類的友元B的派生類C 不能通路A類的private或protect成員變量。但可以通過B提供的接口來通路A。(廢話肯定可以)
[cpp] view plain copy
- #include <iostream>
- using namespace std;
- class B;
- class A
- {
- int a;
- public:
- A(int x=0) { a=x; }
- friend class B;
- };
- class B
- {
- int b;
- public:
- void fun(A& ob){ cout << ob.a << endl;}
- };
- class C:public B
- {
- public:
- //void fun2(A& ob){ cout <<ob.a <<endl;} //派生類新加的函數卻不能通路A,此句會報錯
- };
- void main()
- {
- A a(55);
- C c;
- c.fun(a); //C是B的派生類 通過基類B的函數fun仍然可以通路
- }
1.2. Base的友元可以通過Base的派生類Drived通路Base的private,protect成員變量,但不能通路Drived的private,protect成員變量。(這一點似乎與《C++ primer》裡說的有點沖突)
個人了解:Drived的對象本身就包含Base,Base的友元Frnd自然就可以通路Base的部分。
[cpp] view plain copy
- #include <iostream>
- using namespace std;
- class Base
- {
- int m_a;
- public:
- Base(int x=0){ m_a=x; }
- friend class Frnd;
- };
- class Drived:public Base
- {
- private:
- int m_c;
- public:
- Drived(int x):Base(x){m_c=x;}
- };
- class Frnd
- {
- public:
- void fun(Base& ob) { cout <<ob.m_a << endl; }
- void fun2(Drived& ob)
- {
- cout << ob.m_a<<endl;
- //cout <<ob.m_c<<endl; //編譯錯誤
- }
- };
- int main()
- {
- Drived d(1);
- Frnd f;
- f.fun(d);
- f.fun2(d);
- system("pause");
- return 0;
- }
3 友元類的傳遞問題
A的友元是B,B的友元是C,那A的友元是C? 不是,友元類不具有傳遞性。