浅谈C++类(5)--友元
歡迎轉載,但請標明作者 “九天雁翎”,當然,你給出這個帖子的鏈接更好。
呵呵,又來了,自從我開始嘗試描述類以來,我發現我自己是開始真的了解類了,雖然還不到就明白什么叫oo的高深境界,起碼對于類的使用方法了解的更多了,希望你看了以后也能有所進步啊:)
現在開始講一個有利有弊的東西,友元(friend),我以前講過了private的數據和函數別人是不能直接調用的,這一點對于封裝起到了很重要的作用。但是有的時候總是有調用一個類private成員這樣需要的,那怎么辦呢?C++給了我們友元這個家伙,按我的習慣,首先看個例子。當然,還是我們的水果類:)
例5.1:
?#include <string>
#include <iostream>
using namespace std;
class Fruit?????????????? //定義一個類,名字叫Fruit
{
?string name;???? //定義一個name成員??????????
?string colour;?? //定義一個colour成員
?friend bool isSame(Fruit &,Fruit &);?? //在這里聲明friend友元函數
public:
?void print()????????????? //定義一個輸出名字的成員print()
?{
??cout<<colour<<" "<<name<<endl;
?}
?Fruit(const string &nst = "apple",const string &cst = "green"):name(nst),colour(cst){}? //構造函數
?
?Fruit(){}
};
bool isSame(Fruit &aF,Fruit &bF)
{
?return aF.name == bF.name;??????? //注意,這個函數調用了Fruit的private數據,本來可是不允許的.
}
int main()
{
?Fruit apple;
?Fruit apple2(apple);
?Fruit orange("orange","yellow");
?cout<<"apple = orange ?: "<<isSame(apple,orange)<<endl;?
?cout<<"apple = apple2 ?: "<<isSame(apple,apple2)<<endl;
?
?? ?return 0;
}
?這里,我們聲明了一個isSame()檢測是否同名的函數,而且這不是Fruit類的一個函數,雖然他在類里面聲明了,怎么看出來?假如是類的成員函數,在外部定義必須要Fruit::這樣定義,不是嗎?isSame()沒有這樣,他是個獨立的函數,但是他可以調用Fruit類的私有成員,因為在類里聲明了他是Friend的,這就像你告訴保安(編譯器)某某(isSame)是你的朋友(friend),然后讓他可以進入你的家(調用私有成員)一樣,別人就不允許(非友元函數不允許),這樣說,夠明白嗎?你可以嘗試去掉friend聲明看看編譯錯誤。證明friend的作用:)我這里的得出的編譯錯誤是這樣(error C2248: 'Fruit::name' : cannot access private member declared in class 'Fruit'),也就是name是私有成員,不能調用。不僅可以聲明友元函數,還可以聲明友元類。效果類似。看下面的例子。
例5.2:
#include <string>
#include <iostream>
using namespace std;
class Fruit?????????????? //定義一個類,名字叫Fruit
{
?string name;???? //定義一個name成員??????????
?string colour;?? //定義一個colour成員
?friend class Person;??????? //聲明一個友元類Person
public:
?void print()????????????? //定義一個輸出名字的成員print()
?{
??cout<<colour<<" "<<name;
?}
?Fruit(const string &nst = "apple",const string &cst = "green"):name(nst),colour(cst){}? //構造函數
?
};
class Person???????????? //定義類Person
{
string likedFruit;
public:???????????????????????????????????
?string name;???????????????????????????????????
?bool isLike(Fruit &aF)???????????????????????????????????????????????
?{
??return likedFruit == aF.name;??????????????? //注意,他調用了Fruit類的私有成員,這本來是不允許的
?}
?Person(const string &npe = "jim",const string &lF = "apple"):name(npe),likedFruit(lF){}
};
int main()
{
?Fruit apple;
?Fruit orange("orange","yellow");
?Person jim;
?cout<<"Is "<<jim.name<<"like ";
?apple.print();
?cout<<"? : "<< jim.isLike(apple)<<endl;???? //看看這個函數的調用
?
?? ?return 0;
}
?
bool isSame(Fruit &aF,Fruit &bF,Fruit &cF)
{
?return (aF.name == bF.name)&&(bF.name == cF.name);
}
?具體Person類和程序到底是什么意思,我想只要你看了我以前寫得東西,應該很明白了,就不多注釋和講了,我現在主要是講友元(friend)的用途。另外一點重載函數的話,你想讓幾個成為友元就讓幾個,其他的將不是友元函數,這里提醒一下,重載函數其實可是各自獨立的函數,只不過在C++中為了調用方便,讓他們叫同一個名字而已。你不相信,可以自己試試。比如說在例5.1中,假如你重載一個但是卻不聲明為友元,編譯是通不過的。你必須這樣各自聲明。見下例。
例5.3:
#include <string>
#include <iostream>
using namespace std;
class Fruit?????????????? //定義一個類,名字叫Fruit
{
?string name;???? //定義一個name成員??????????
?string colour;?? //定義一個colour成員
?friend bool isSame(Fruit &aF,Fruit &bF);????????????????????????? //聲明為友元
?friend bool isSame(Fruit &aF,Fruit &bF,Fruit &cF);???????? //再次聲明為友元
public:
?void print()????????????? //定義一個輸出名字的成員print()
?{
??cout<<colour<<" "<<name;
?}
?Fruit(const string &nst = "apple",const string &cst = "green"):name(nst),colour(cst){}? //構造函數
?
};
bool isSame(Fruit &aF,Fruit &bF)
{
?return aF.name == bF.name;
}
bool isSame(Fruit &aF,Fruit &bF,Fruit &cF)
{
?return (aF.name == bF.name)&&(bF.name == cF.name);
}
int main()
{
?Fruit apple;
?Fruit apple2;
?Fruit apple3;
?Fruit orange("orange","yellow");
?cout<<isSame(apple,apple2)<<isSame(apple,apple2,orange)<<endl;
?return 0;
}
?
現在再回過來看例4.0。
#include <string>
#include <iostream>
using namespace std;
class Fruit?????????????? //定義一個類,名字叫Fruit
{
?string name;???? //定義一個name成員??????????
?string colour;?? //定義一個colour成員
?
public:
?bool isSame(const Fruit &otherFruit)?? //期待的形參是另一個Fruit類對象,測試是否同名
?{
??return name == otherFruit.name;
?}
?void print()????????????? //定義一個輸出名字的成員print()
?{
??cout<<colour<<" "<<name<<endl;
?}
?Fruit(const string &nst,const string &cst = "green"):name(nst),colour(cst){}? //構造函數
?
?Fruit(){}
};
int main()
{
?Fruit apple("apple");
?Fruit orange("orange");
?cout<<"apple = orange ?: "<<apple.isSame(orange)<<endl;? //沒有問題,肯定不同
?cout<<"apple = /"apple/" ?:"<<apple.isSame(string("apple")); //用一個string做形參?
?
?? ?return 0;
}
除了隱式類類型轉換外你還發現什么沒有?恩,就是isSame()函數他直接調用了另一個引用的Fruit對象的私有成員name,這個按道理是不允許的啊,不過,注意的是,他本身就是Fruit類,所以,我個人看法(純粹個人看法),這里可以認為一個類,自動聲明為自己類的友元。呵呵,不知道對不對。假如你想這樣定義,
bool Fruit::isSame(const string &otherName)?
{
??return name == otherName;
?}
?然后這樣調用,?cout<<apple.isSame(apple2.name)<<endl;結果是通不過編譯的,道理還是不能調用一個類的私有成員。最后要說的是,我以前以為友元雖然為我們帶來了一定的方便,但是友元的破壞性也是巨大的,他破壞了類的封裝,不小心使用的話,會打擊你對C++類安全使用的信心,就像強制類型轉換一樣,能不用就不用。但是當我看了Bjarne Stroustrup 的書后,才理解了一些東西,他的意思就是友元是沒有人們說的那樣的破壞性的,因為友元的聲明權完全在類設計者手里,他能很好控制,而不會讓友元的特性泛濫,而且在我學的更多一些后,發現友元在一些應用中必須得用到,比如一些操作符的重載,不用友元就不行,雖然個人感覺,類中成員函數省略的This形參假如沒有友元作補充支撐,根本就不敢用,因為會限制很多功能,當然有了友元就沒有關系了,可以在外面定義嘛。友元就講了這么多,不知道是不是復雜化了。?
總結
以上是生活随笔為你收集整理的浅谈C++类(5)--友元的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 浅谈C++类(7)--析构函数
- 下一篇: 浅谈C++类(6)--复制构造函数