一篇文章詳細(xì)解釋C++的友元(friend)
一.友元函數(shù)
友元函數(shù)可以是普通函數(shù)或者類成員函數(shù)。
先看普通函數(shù)聲明為友元函數(shù):
如下所示:
#include <iostream> #include <cmath> using namespace std; class Point { //普通函數(shù)聲明為類的友元函數(shù) friend double TwoPointsDistant(const Point& pnt1, const Point& pnt2); public: Point(double x=0, double y=0) :_x(x), _y(y) {} double getPointXAxis() const { return this->_x; } double getPointYAxis() const { return this->_y; } private: double _x; double _y; }; //計(jì)算兩點(diǎn)的距離 double TwoPointsDistant(const Point& pnt1, const Point& pnt2) { return sqrt( pow((pnt1._x - pnt2._x), 2) + pow((pnt1._y - pnt2._y), 2) ); } int main() { Point point1(1.1,2.2); Point point2(3.3, 4.4); cout << TwoPointsDistant(point1, point2) << endl; system("pause"); return 0; }
這里說(shuō)明一點(diǎn):TwoPointsDistant()函數(shù)必須在Point類的定義下面
,至于原因,很簡(jiǎn)單,你若放在Point上面,Point的數(shù)據(jù)成員_x和_y都沒(méi)定義呢,你用個(gè)錘子。
再看類成員函數(shù)聲明為友元函數(shù):
還以上面的類為例,現(xiàn)在加一個(gè)_PointMove_類,它有一個(gè)成員函數(shù)_PointAxisAddOne,_作用是將點(diǎn)的坐標(biāo)都加1。如下:
class PointMove { public: void PointAxisAddOne(Point& pnt); };
這里就出現(xiàn)了一個(gè)問(wèn)題:_Point_和_PointMove_哪個(gè)放在前面?先給出答案,應(yīng)該把_PointMove_放在前面,并且是必須的,如下:
class Point;//前向聲明Point class PointMove { public: void PointAxisAddOne(Point& pnt); }; class Point { //普通函數(shù)聲明為類的友元函數(shù) friend double TwoPointsDistant(const Point& pnt1, const Point& pnt2); //類成員函數(shù)聲明為友元 friend void PointMove::PointAxisAddOne(Point& pnt); /*這里同前*/ }; //類成員函數(shù)的定義 void PointMove::PointAxisAddOne(Point& pnt) { pnt._x = pnt._x + 1; pnt._y = pnt._y + 1; }
這里注意,對(duì)于類的成員函數(shù),聲明為其他類的友元函數(shù)時(shí)需要加上類的作用域,即指出該函數(shù)屬于哪個(gè)類。如上面的_PointMove::_。?
同時(shí),需要說(shuō)明的是,PointAxisAddOne()函數(shù)的定義是必須放在Point類定義后面的,這和普通函數(shù)的道理是一樣的。
最后說(shuō)明
1.一個(gè)函數(shù)Func被聲明為類A的友元函數(shù),那么是不能直接使用this指針來(lái)訪問(wèn)類A的數(shù)據(jù)成員的(當(dāng)然,若Func是類B的成員函數(shù),它可以通過(guò)this訪問(wèn)類B的數(shù)據(jù)成員),這和成員函數(shù)不同。
2.一個(gè)函數(shù)Func為什么要聲明為某個(gè)類A的友元,就是因?yàn)?code>函數(shù)的參數(shù)類型為類A類型,我想訪問(wèn)這個(gè)類對(duì)象的數(shù)據(jù)成員,所以被聲明為類A的友元函數(shù)的參數(shù)類型必定為類A,如friend Func(A& obj);
二.友元類
若是將一個(gè)類C都聲明為另一個(gè)類A的友元類,則類C中的成員函數(shù)均可訪問(wèn)類A中的私有數(shù)據(jù)成員。如下:
class Point { //友元類 friend class PointInfo; ... } class PointInfo { public: //打印點(diǎn)所處象限 void PrintQuadrant(const Point& pnt) const { if (pnt._x > 0 && pnt._y > 0) cout << "點(diǎn)"<<"(" << pnt._x << "," << pnt._y<<")" <<"處于第一象限" << endl; } };
當(dāng)然,你也可以把_PointInfo_寫在_Point_前,只是函數(shù)_PrintQuadrant()_的定義就不能在類內(nèi)實(shí)現(xiàn)了,只能在_Point_后實(shí)現(xiàn),原因和前面一樣,不再贅述。
三.完整示例:
#include <iostream> #include <cmath> using namespace std; class Point; class PointMove { public: void PointAxisAddOne(Point& pnt); }; class PointInfo { public: //打印點(diǎn)所處象限 void PrintQuadrant(const Point& pnt) const; }; class Point { friend class PointInfo; friend double TwoPointsDistant(const Point& pnt1, const Point& pnt2); friend void PointMove::PointAxisAddOne(Point& pnt); public: Point(double x=0, double y=0) :_x(x), _y(y) {} double getPointXAxis() const { return this->_x; } double getPointYAxis() const { return this->_y; } void PrintAxis(const Point& pnt) const { } private: double _x; double _y; }; //打印點(diǎn)所處象限 void PointInfo::PrintQuadrant(const Point& pnt) const { if (pnt._x > 0 && pnt._y > 0) cout << "點(diǎn)"<<"(" << pnt._x << "," << pnt._y<<")" <<"處于第一象限" << endl; } void PointMove::PointAxisAddOne(Point& pnt) { pnt._x = pnt._x + 1; pnt._y = pnt._y + 1; } double TwoPointsDistant(const Point& pnt1, const Point& pnt2) { return sqrt( pow((pnt1._x - pnt2._x), 2) + pow((pnt1._y - pnt2._y), 2) ); } int main() { Point point1(1.1,2.2); Point point2(3.3, 4.4); cout << TwoPointsDistant(point1, point2) << endl; PointInfo pf; pf.PrintQuadrant(point1); system("pause"); return 0; }
VS2015打印結(jié)果:
四.同一個(gè)類(class)的類對(duì)象(object)互為友元
還以上面給出的例子為基礎(chǔ),現(xiàn)在在_Point_類加一個(gè)成員函數(shù)func(const Point& pnt),它返回點(diǎn)的x軸和y軸的和。如下所示。
class Point { /*這里同上*/ double func(const Point& pnt) { return pnt._x + pnt._y; } private: double _x; double _y; };
現(xiàn)在我生成兩個(gè)對(duì)象,并作如下操作:
Point point1(1.1,2.2); Point point2(3.3, 4.4); cout << point1.func(point2) << endl;
最后的結(jié)果是打印出7.7??吹竭@里不知道你有沒(méi)有疑問(wèn):為什么可以通過(guò)point1直接訪問(wèn)point2的私有數(shù)據(jù)成員,而沒(méi)有將func()聲明為友元函數(shù)?侯捷老師是這么解釋的:相同class的各個(gè)objects之間互為友元。
所以對(duì)于一個(gè)類A,若有一個(gè)成員函數(shù)Fun(A& arg),可以通過(guò)arg直接訪問(wèn)A的私有數(shù)據(jù)成員。
總結(jié)
本篇文章就到這里了,希望能夠給你帶來(lái)幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
探究在C++程序并發(fā)時(shí)保護(hù)共享數(shù)據(jù)的問(wèn)題
這篇文章主要介紹了探究在C++程序并發(fā)時(shí)保護(hù)共享數(shù)據(jù)的問(wèn)題,也有利于大家更好地理解C++多線程的一些機(jī)制,需要的朋友可以參考下2015-07-07C++實(shí)現(xiàn)約瑟夫環(huán)的循環(huán)單鏈表
這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)約瑟夫環(huán)的循環(huán)單鏈表,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-10-10C語(yǔ)言基礎(chǔ)解析之分支與循環(huán)語(yǔ)句
C語(yǔ)言是一門結(jié)構(gòu)化的程序設(shè)計(jì)語(yǔ)言,當(dāng)C語(yǔ)言用來(lái)描述生活中的事物時(shí),會(huì)用到三種結(jié)構(gòu):順序結(jié)構(gòu)(不去贅述),選擇結(jié)構(gòu)(對(duì)應(yīng)分支語(yǔ)句),循環(huán)結(jié)構(gòu)(對(duì)應(yīng)循環(huán)語(yǔ)句),分支語(yǔ)句:分支語(yǔ)句分為兩種,一種是if語(yǔ)句,一種是switch語(yǔ)句2021-09-09c++動(dòng)態(tài)內(nèi)存空間示例(自定義空間類型大小和空間長(zhǎng)度)
這篇文章主要介紹了c++動(dòng)態(tài)內(nèi)存空間示例,自定義空間類型大小和空間長(zhǎng)度,需要的朋友可以參考下2014-04-04C++日期類(Date)實(shí)現(xiàn)的示例代碼
這篇文章主要為大家詳細(xì)介紹了如何利用C++語(yǔ)言實(shí)現(xiàn)日期類(Date),可以實(shí)現(xiàn)確定某年某月有多少天、打印日期等功能,感興趣的可以了解一下2022-07-07