9.4 友元

    一般来说,类的公有成员能够在类外访问,私有的成员只能被类的其他成员函数访问。在C++中,可以定义友元,如果某一个函数定义为类的友元,则该函数就可以访问该类的私有成员,同时,也可以把一个类定义为另一个类的友元,本节将讨论友元函数和友元类的概念。

    9.4.1 友元的非成员函数

    如果在某个类的定义中用friend声明了一个外部函数(或者是其他类的函数成员,既可以是public型,也可以是private型)后,这个外部函数称为类的友元函数。

    友元函数声明的基本格式如下所示。


    friend函数原型;

    注意

    用下面的比喻形容友元函数可能比较恰当,将类比作一个家庭,类的private成员相当于家庭的秘密,一般的外人是不允许探听这些秘密的,只有friend(朋友)才有能力探听这些秘密。

    非成员形式的友元函数如代码9.4所示。

    代码9.4 友元之非成员函数NonMemberFriend


    <———————————————-文件名:point.h———————————————> 01 #include<iostream> 02 using namespace std; 03 class point//point类定义 04 { 05 private: 06 int x,y; 07 //友元函数的声明,声明位置没有关系,可以是public,也可是private 08 friend float dis(point&p1,point&p2); 09 public: 10 point(int i=0,int j=0)//构造函数,带默认参数值 11 { 12 x=i; 13 y=j; 14 } 15 void disp()//成员函数 16 { 17 cout<<"("<<x<<","<<y<<")"; 18 } 19 }; <————————————-文件名:example904.cpp——————————————-> 20 #include"point.h" 21 #include<cmath>//使用计算平方根的函数sqrt要用到的头文件 22 int main() 23 { 24 point p1(1,2),p2(4,5);//声明两个point类的对象p1和p2 25 p1. disp();//显示点p1的信息 26 cout<<"与"; 27 p2. disp();//显示点p2的信息 28 cout<<"距离="<<dis(p1,p2)<<endl;//利用友元函数计算两点举例 29 return 0; 30 } 31 float dis(point&p1,point&p2)//友元函数的实现 32 { 33 float d; 34 d=sqrt((p1. x-p2.x)(p1.x-p2.x)+(p1.y-p2.y)(p1.y-p2.y)); 35 //友元函数中可访问类的private成员 36 return d; 37 }

    输出结果如下所示。


    (1,2)与(4,5)距离=4.24264

    【代码解析】代码第31行的dis函数是外部函数,不属于任何一个类,此时,只要在Point类内,即代码第8行使用语句“friend float dis(point&p1,point&p2);”对其进行声明即可,这样,dis函数便称为point类的友元函数,可以在dis函数中访问类的private成员。

    非成员函数的友元函数有如下特点。

    (1)在类内只需对函数进行声明,声明位置没有要求,可以出现在类的任何地方,包括在private和public部分。

    (2)函数定义要放在类外,具体定义位置没有要求。

    (3)友元函数不能直接访问类的成员,必须通过访问对象来实现,为此,必须传递类对象作为函数参数,采用传值、传指针或传引用方式均可,出于对程序执行效率的考虑,建议使用类对象的引用作为参数。

    (4)友元函数不是类的成员函数,所以友元函数的实现和普通函数一样,在实现时不用“:”指示属于哪个类,只有成员函数才使用“:”作用域符号。

    (5)一个函数可以同时作为多个类的友元函数。

    细心的读者可能会发现,在代码9.4的example904.cpp中,并没有在使用dis函数前对其声明,这似乎违反了前面讲过的规则,实际上,在类定义中已经声明了dis函数,编译器已经知道了dis函数的存在,example904.cpp中的dis函数声明因此可以省略。