淺談C++類(5)–友元

來源:互聯網
上載者:User

歡迎轉載,但請標明作者 “九天雁翎”,當然,你給出這個文章的連結更好。

呵呵,又來了,自從我開始嘗試描述類以來,我發現我自己是開始真的瞭解類了,雖然還不到就明白什麼叫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形參假如沒有友元作補充支撐,根本就不敢用,因為會限制很多功能,當然有了友元就沒有關係了,可以在外面定義嘛。友元就講了這麼多,不知道是不是複雜化了。 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.