当前位置:嗨网首页>书籍在线阅读

07-友元

  
选择背景色: 黄橙 洋红 淡粉 水蓝 草绿 白色 选择字体: 宋体 黑体 微软雅黑 楷体 选择字体大小: 恢复默认

11.3 友元

您知道,C++控制对类对象私有部分的访问。通常,公有类方法提供唯一的访问途径,但是有时候这种限制太严格,以致于不适合特定的编程问题。在这种情况下,C++提供了另外一种形式的访问权限:友元。友元有3种:

  • 友元函数;
  • 友元类;
  • 友元成员函数。

通过让函数成为类的友元,可以赋予该函数与类的成员函数相同的访问权限。下面介绍友元函数,其他两种友元将在第15章介绍。

介绍如何成为友元前,先介绍为何需要友元。在为类重载二元运算符时(带两个参数的运算符)常常需要友元。将Time对象乘以实数就属于这种情况,下面来看看。

在前面的Time类示例中,重载的乘法运算符与其他两种重载运算符的差别在于,它使用了两种不同的类型。也就是说,加法和减法运算符都结合两个Time值,而乘法运算符将一个Time值与一个double值结合在一起。这限制了该运算符的使用方式。记住,左侧的操作数是调用对象。也就是说,下面的语句:

A = B * 2.75;

将被转换为下面的成员函数调用:

A = B.operator*(2.75);

但下面的语句又如何呢?

A = 2.75 * B; // cannot correspond to a member function

从概念上说,2.75 B应与B 2.75相同,但第一个表达式不对应于成员函数,因为2.75不是Time类型的对象。记住,左侧的操作数应是调用对象,但2.75不是对象。因此,编译器不能使用成员函数调用来替换该表达式。

解决这个难题的一种方式是,告知每个人(包括程序员自己),只能按B 2.75这种格式编写,不能写成2.75 B。这是一种对服务器友好-客户警惕的(server-friendly, client-beware)解决方案,与OOP无关。

然而,还有另一种解决方式——非成员函数(记住,大多数运算符都可以通过成员或非成员函数来重载)。非成员函数不是由对象调用的,它使用的所有值(包括对象)都是显式参数。这样,编译器能够将下面的表达式:

A = 2.75 * B; // cannot correspond to a member function

与下面的非成员函数调用匹配:

A = operator*(2.75, B);

该函数的原型如下:

Time operator*(double m, const Time & t);

对于非成员重载运算符函数来说,运算符表达式左边的操作数对应于运算符函数的第一个参数,运算符表达式右边的操作数对应于运算符函数的第二个参数。而原来的成员函数则按相反的顺序处理操作数,也就是说,double值乘以Time值。

使用非成员函数可以按所需的顺序获得操作数(先是double,然后是Time),但引发了一个新问题:非成员函数不能直接访问类的私有数据,至少常规非成员函数不能访问。然而,有一类特殊的非成员函数可以访问类的私有成员,它们被称为友元函数。