友元
友元除了前面讲过的函数以外,友元还可以是类,即一个类可以作另一个类的友元。当一个类作为另一个类的友元时,这就意味着这个类的所有成员函数都是另一个类的友元函数。
让我们回顾一下重载的“等于操作符的”定义,它是为名字空间域中定义的String 类而提供的,针对两个String 对象的“等于操作符”如下:
1 2 3 4 5 6 | bool operator==( const String &str1, const String &str2 ) { if ( str1.size() != str2.size() ) return false; return strcmp( str1.c_str(), str2.c_str() ) ? false : true; } |
把这个定义与被定义为成员函数的操作符定义相比较:
1 2 3 4 5 6 | bool String::operator==( const String &rhs ) const { if ( _size != rhs._size ) return false; return strcmp( _string, rhs._string ) ? false : true; } |
你看到区别了吗?我们注意到必须要修改函数定义内部对于String 类私有数据成员的引用方式。因为新的等于操作符是全局函数,不是类成员函数,它不能直接引用String 的私有数据成员,它使用访问成员函数size()和c_str()来获得String 对象的大小,以及底层的C 风格字符串。
另外一种可能的实现是把全局“等于操作符”声明为String 类的友元friend。通过把函数或操作符声明为友元,一个类可以授予这个函数或操作符访问其非公有成员的权利。
友元声明以关键字friend 开始,它只能出现在类定义中。因为友元不是授权类的成员,所以它不受其所在类的声明区域public private 和protected 的影响。这里我们选择把所有友元声明组织在一起并放在类头之后:
1 2 3 4 5 6 7 8 | class String { friend bool operator==( const String &, const String & ); friend bool operator==( const char *, const String & ); friend bool operator==( const String &, const char * ); public: // ... String 类中的其他部分 }; |
String 类中的三个友元声明把全局域中声明的三个重载的“比较操作符”(在上节介绍)声明为String 类的友
元既然这些等于操作符已经被声明为友元那么它们的定义就可以直接引用String 的私有成员了。
1 2 3 4 5 6 7 8 9 10 11 12 13 | // friend 操作符直接引用 String 的私有成员 // friend operators: refer to String private members directly bool operator==( const String &str1, const String &str2 ) { if ( str1._size != str2._size ) return false; return strcmp( str1._string, str2._string ) ? false : true; } inline bool operator==( const String &str, const char *s ) { return strcmp( str._string, s ) ? false : true; } // 以下略 |