1、友元函数是可以直接访问类的私有成员的非成员函数。
【资料图】
2、它是定义在类外的普通函数,它不属于任何类,但需要在类的定义中加以声明,声明时只需在友元的名称前加上关键字friend,其格式如下:friend 类型 函数名(形式参数);友元函数的声明可以放在类的私有部分,也可以放在公有部分,它们是没有区别的,都说明是该类的一个友元函数。
3、一个函数可以是多个类的友元函数,只需要在各个类中分别声明。
4、友元函数的调用与一般函数的调用方式和原理一致。
5、友元函数虽然不是类成员却能够访问类的所有成员的函数。
6、类授予它的友元特别的访问权。
7、通常同一个开发者会出于技术和非技术的原因,控制类的友元和成员函数(否则当你想更新你的类时,还要征得其它部分的拥有者的同意)。
8、举例:看下面表示有理数的一个类:class rational {public:rational(int numerator = 0,int denominator = 1);int numerator() const;int denominator() const;private:...};这是一个没有一点用处的类。
9、(用条款18的术语来说,接口的确最小,但远不够完整。
10、)所以,要对它增加加,减,乘等算术操作支持,但是,该用成员函数还是非成员函数,或者,非成员的友元函数来实现呢?当拿不定主意的时候,用面向对象的方法来考虑!有理数的乘法是和rational类相联系的,所以,写一个成员函数把这个操作包到类中。
11、class rational {public:...const rational operator*(const rational& rhs) const;};(如果你不明白为什么这个函数以这种方式声明--返回一个const值而取一个const的引用作为它的参数--参考条款21-23。
12、)条款21: 尽可能使用const条款22: 尽量用"传引用"而不用"传值"条款23: 必须返回一个对象时不要试图返回一个引用可以很容易地对有理数进行乘法操作:rational oneeighth(1,8);rational onehalf(1,2);rational result = onehalf * oneeighth; // 运行良好result = result * oneeighth; // 运行良好但不要满足,还要支持混合类型操作,比如,rational要能和int相乘。
13、但当写下下面的代码时,只有一半工作:result = onehalf * 2; // 运行良好result = 2 * onehalf; // 出错!这是一个不好的苗头。
14、记得吗?乘法要满足交换律。
15、如果用下面的等价函数形式重写上面的两个例子,问题的原因就很明显了:result = onehalf.operator*⑵; // 运行良好result = 2.operator*(onehalf); // 出错!对象onehalf是一个包含operator*函数的类的实例,所以编译器调用了那个函数。
16、而整数2没有相应的类,所以没有operator*成员函数。
17、编译器还会去搜索一个可以象下面这样调用的非成员的operator*函数(即,在某个可见的名字空间里的operator*函数或全局的operator*函数):result = operator*(2,onehalf); // 错误!但没有这样一个参数为int和rational的非成员operator*函数,所以搜索失败。
18、再看看那个成功的调用。
19、它的第二参数是整数2,然而rational::operator*期望的参数却是rational对象。
20、怎么回事?为什么2在一个地方可以工作而另一个地方不行?秘密在于隐式类型转换。
21、编译器知道传的值是int而函数需要的是rational,但它也同时知道调用rational的构造函数将int转换成一个合适的rational,所以才有上面成功的调用(见条款m19)。
22、换句话说,编译器处理这个调用时的情形类似下面这样:const rational temp⑵; // 从2产生一个临时// rational对象result = onehalf * temp; // 同onehalf.operator*(temp);当然,只有所涉及的构造函数没有声明为explicit的情况下才会这样,因为explicit构造函数不能用于隐式转换,这正是explicit的含义。
23、如果rational象下面这样定义:class rational {public:explicit rational(int numerator = 0,// 此构造函数为int denominator = 1); // explicit...const rational operator*(const rational& rhs) const;...};那么,下面的语句都不能通过编译:result = onehalf * 2; // 错误!result = 2 * onehalf; // 错误!这不会为混合运算提供支持,但至少两条语句的行为一致了。
24、扩展资料:我们已知道类具有封装和信息隐藏的特性。
25、只有类的成员函数才能访问类的私有成员,程序中的其他函数是无法访问私有成员的。
26、非成员函数可以访问类中的公有成员,但是如果将数据成员都定义为公有的,这又破坏了隐藏的特性。
27、另外,应该看到在某些情况下,特别是在对某些成员函数多次调用时,由于参数传递,类型检查和安全性检查等都需要时间开销,而影响程序的运行效率。
28、为了解决上述问题,提出一种使用友元的方案。
29、友元是一种定义在类外部的普通函数,但它需要在类体内进行说明,为了与该类的成员函数加以区别,在说明时前面加以关键字friend。
30、友元不是成员函数,但是它可以访问类中的私有成员。
31、友元的作用在于提高程序的运行效率,但是,它破坏了类的封装性和隐藏性,使得非成员函数可以访问类的私有成员。
32、友元可以是一个函数,该函数被称为友元函数;友元也可以是一个类,该类被称为友元类。
33、参考资料:Friend(友元函数)_百度百科。
本文分享完毕,希望对大家有所帮助。
标签: