望城經(jīng)濟建設開區(qū)門戶網(wǎng)站百度電腦版網(wǎng)址
概述
????????我們知道,C++的類具有封裝和信息隱藏的特性。一般情況下,我們會封裝public的成員函數(shù)供用戶調(diào)用,而將成員變量設置為private或protected。但在一些比較復雜的業(yè)務情況下,可能需要去訪問對象中大量的private或protected成員變量。如果為這些private或protected成員變量都封裝public成員函數(shù),無疑是比較麻煩的,有時候還會影響程序的執(zhí)行效率。此時,友元函數(shù)就派上了用場。
????????這就好比我們的房間安裝了一個指紋鎖,陌生人是無法進入房間內(nèi)部的。但我們的好朋友有時候需要去一下房間,此時,可以把好朋友的指紋也錄入指紋鎖里面。這樣,好朋友就可以順利進入房間了。
基本規(guī)則
????????1、一個類的友元可以是函數(shù)(稱為友元函數(shù)),也可以是另一個類(稱為友元類)。
????????2、要為一個類聲明友元時,需要在類聲明中友元函數(shù)或友元類的前面加上friend關鍵字。類中友元的位置沒有關系,放在public、protected和private均可。
class CBase
{friend class CFriend; // 友元類friend void FriendFunc(CBase &base); // 友元函數(shù)
public:CBase();private:void Show();protected:std::string m_strText;private:int m_nNumber;
};CBase::CBase() : m_strText("CSDN"), m_nNumber(66)
{NULL;
}void CBase::Show()
{printf("info is: %s, %d\n", m_strText.c_str(), m_nNumber);
}
????????3、友元函數(shù)的原型雖然在類的聲明中出現(xiàn)過,但友元函數(shù)不是類的成員函數(shù),不能訪問類對象的this指針。
CBase base;
base.FriendFunc(base); // 友元函數(shù)不是類的成員函數(shù),會發(fā)生編譯錯誤
????????4、友元函數(shù)或友元類的定義均在類的外部,但有權訪問類的private和protected成員。
void FriendFunc(CBase &base)
{base.Show(); // 訪問私有成員函數(shù)base.m_strText = "Welcome"; // 訪問受保護成員變量base.m_nNumber = 99; // 訪問私有成員變量
}
????????5、基類的友元屬性不能被派生類繼承,就好比你有一個好朋友,但這個好朋友不一定是你兒子和孫子的好朋友。
????????6、友元破壞了類的封裝性和隱藏性,非必要的情況下,不建議使用,更不能濫用。
全局友元函數(shù)
????????將全局函數(shù)作為類的友元函數(shù),此時,該友元函數(shù)可以訪問類對象的private或protected成員,也可以訪問類的private或protected靜態(tài)成員。可參看下面的示例代碼。
class CBase
{friend void FriendFunc(CBase &base);
public:CBase();private:void Show();protected:std::string m_strText;private:int m_nNumber;static int m_sData;
};int CBase::m_sData = 88;CBase::CBase() : m_strText("CSDN"), m_nNumber(66)
{NULL;
}void CBase::Show()
{printf("info is: %s, %d\n", m_strText.c_str(), m_nNumber);
}void FriendFunc(CBase &base)
{base.Show();base.m_strText = "Welcome";base.m_nNumber = 99;base.Show();printf("data is: %d\n", CBase::m_sData);
}CBase base;
FriendFunc(base);
????????上述示例代碼的輸出如下:
info is: CSDN, 66
info is: Welcome, 99
data is: 88
友元類
????????將另一個類作為類的友元類,此時,該友元類可以訪問類對象的private或protected成員,也可以訪問類的private或protected靜態(tài)成員??蓞⒖聪旅娴氖纠a。
class CBase
{friend class CFriend;
public:CBase();private:void Show();protected:std::string m_strText;private:int m_nNumber;static int m_sData;
};int CBase::m_sData = 88;CBase::CBase() : m_strText("CSDN"), m_nNumber(66)
{NULL;
}void CBase::Show()
{printf("info is: %s, %d\n", m_strText.c_str(), m_nNumber);
}class CFriend
{
public:void ShowBase1(const CBase &base);void ShowBase2();
};void CFriend::ShowBase1(const CBase &base)
{printf("friend base1: %s, %d\n", base.m_strText.c_str(), base.m_nNumber);
}void CFriend::ShowBase2()
{printf("friend base2: %d\n", CBase::m_sData);
}CBase base;
CFriend fri;
fri.ShowBase1(base);
fri.ShowBase2();
????????上述示例代碼的輸出如下:
friend base1: CSDN, 66
friend base2: 88
類的成員函數(shù)作為友元
????????申明友元類時,友元類中的所有函數(shù)都可以訪問類的private或protected成員。為了限制訪問權限,可以只允許類的特定成員函數(shù)作為友元函數(shù)??蓞⒖聪旅娴氖纠a。
class CBase;class CFriend
{
public:void ShowBase1(const CBase &base);void ShowBase2();
};class CBase
{friend void CFriend::ShowBase1(const CBase &base);
public:CBase();private:void Show();protected:std::string m_strText;private:int m_nNumber;static int m_sData;
};int CBase::m_sData = 88;CBase::CBase() : m_strText("CSDN"), m_nNumber(66)
{NULL;
}void CBase::Show()
{printf("info is: %s, %d\n", m_strText.c_str(), m_nNumber);
}void CFriend::ShowBase1(const CBase &base)
{printf("friend base1: %s, %d\n", base.m_strText.c_str(), base.m_nNumber);
}void CFriend::ShowBase2()
{// 編譯出錯,因為CFriend::ShowBase2不是CBase的友元,無法訪問私有的靜態(tài)變量printf("friend base2: %d\n", CBase::m_sData);
}CBase base;
CFriend fri;
fri.ShowBase1(base);
fri.ShowBase2();
運算符重載中使用友元
????????友元的使用場景,一個是聯(lián)系緊密、協(xié)調(diào)工作的類與函數(shù)、類與類之間,另一個就是運算符重載。可參看下面的示例代碼。
class CBase
{friend std::ostream &operator<< (std::ostream &out, const CBase &base);
public:CBase();protected:std::string m_strText;private:int m_nNumber;
};CBase::CBase() : m_strText("CSDN"), m_nNumber(66)
{NULL;
}std::ostream &operator<< (std::ostream &out, const CBase &base)
{// 運算符重載函數(shù)作為CBase的友元函數(shù),可訪問CBase內(nèi)的私有成員和受保護成員out << "base dump: " << base.m_strText.c_str() << "," << base.m_nNumber;return out;
}CBase base;
std::cout << base << std::endl; // 輸出為:base dump: CSDN,66