友元函數和友元類在實際開發中較少使用,想快速學習C++的讀者可以跳過本節。一個類中可以有 public、protected、private 三種屬性的成員,通過對象可以訪問 public 成員,只有本類中的函數可以訪問本類的 private 成員。現在,我們來介紹一種例外情況——友元(friend)。借助友元(friend),可以使得其他類中的成員函數以及全局范圍內的函數訪問當前類的 private 成員。
#include <iostream> using namespace std; class Student{ public: Student(char *name, int age, float score); public: friend void show(Student *pstu); //將show()聲明為友元函數 private: char *m_name; int m_age; float m_score; }; Student::Student(char *name, int age, float score): m_name(name), m_age(age), m_score(score){ } //非成員函數 void show(Student *pstu){ cout<<pstu->m_name<<"的年齡是 "<<pstu->m_age<<",成績是 "<<pstu->m_score<<endl; } int main(){ Student stu("小明", 15, 90.6); show(&stu); //調用友元函數 Student *pstu = new Student("李磊", 16, 80.5); show(pstu); //調用友元函數 return 0; }運行結果:
void show(){ cout<<m_name<<"的年齡是 "<<m_age<<",成績是 "<<m_score<<endl; }成員函數在調用時會隱式地增加 this 指針,指向調用它的對象,從而使用該對象的成員;而 show() 是非成員函數,沒有 this 指針,編譯器不知道使用哪個對象的成員,要想明確這一點,就必須通過參數傳遞對象(可以直接傳遞對象,也可以傳遞對象指針或對象引用),並在訪問成員時指明對象。
#include <iostream> using namespace std; class Address; //提前聲明Address類 //聲明Student類 class Student{ public: Student(char *name, int age, float score); public: void show(Address *addr); private: char *m_name; int m_age; float m_score; }; //聲明Address類 class Address{ private: char *m_province; //省份 char *m_city; //城市 char *m_district; //區(市區) public: Address(char *province, char *city, char *district); //將Student類中的成員函數show()聲明為友元函數 friend void Student::show(Address *addr); }; //實現Student類 Student::Student(char *name, int age, float score): m_name(name), m_age(age), m_score(score){ } void Student::show(Address *addr){ cout<<m_name<<"的年齡是 "<<m_age<<",成績是 "<<m_score<<endl; cout<<"家庭住址:"<<addr->m_province<<"省"<<addr->m_city<<"市"<<addr->m_district<<"區"<<endl; } //實現Address類 Address::Address(char *province, char *city, char *district){ m_province = province; m_city = city; m_district = district; } int main(){ Student stu("小明", 16, 95.5f); Address addr("陝西", "西安", "雁塔"); stu.show(&addr); Student *pstu = new Student("李磊", 16, 80.5); Address *paddr = new Address("河北", "衡水", "桃城"); pstu -> show(paddr); return 0; }運行結果:
'Address' has not been declared
。類的提前聲明和函數的提前聲明是一個道理。Address addr; //企圖使用不完整的類來創建對象
因為創建對象時要為對象分配內存,在正式聲明類之前,編譯器無法確定應該為對象分配多大的內存。編譯器只有在“見到”類的正式聲明後(其實是見到成員變量),才能確定應該為對象預留多大的內存。在對一個類作了提前聲明後,可以用該類的名字去定義指向該類型對象的指針變量(本例就定義了 Address 類的指針變量)或引用變量(後續會介紹引用),因為指針變量和引用變量本身的大小是固定的,與它所指向的數據的大小無關。#include <iostream> using namespace std; class Address; //提前聲明Address類 //聲明Student類 class Student{ public: Student(char *name, int age, float score); public: void show(Address *addr); private: char *m_name; int m_age; float m_score; }; //聲明Address類 class Address{ public: Address(char *province, char *city, char *district); public: //將Student類聲明為Address類的友元類 friend class Student; private: char *m_province; //省份 char *m_city; //城市 char *m_district; //區(市區) }; //實現Student類 Student::Student(char *name, int age, float score): m_name(name), m_age(age), m_score(score){ } void Student::show(Address *addr){ cout<<m_name<<"的年齡是 "<<m_age<<",成績是 "<<m_score<<endl; cout<<"家庭住址:"<<addr->m_province<<"省"<<addr->m_city<<"市"<<addr->m_district<<"區"<<endl; } //實現Address類 Address::Address(char *province, char *city, char *district){ m_province = province; m_city = city; m_district = district; } int main(){ Student stu("小明", 16, 95.5f); Address addr("陝西", "西安", "雁塔"); stu.show(&addr); Student *pstu = new Student("李磊", 16, 80.5); Address *paddr = new Address("河北", "衡水", "桃城"); pstu -> show(paddr); return 0; }第 24 行代碼將 Student 類聲明為 Address 類的友元類,聲明語句為:
friend class Student;
有的編譯器也可以不寫 class 關鍵字,不過為了增強兼容性還是建議寫上。