一般来说,访问私有类成员的唯一方法是使用类方法 。C++使用友元函数来避开这种限制。要让函数 成为友元,需要在类声明中声明该函数,并在声明前加上关键字f riend。
C++扩展了对运算符的重载,允许自定义特殊的运算符函数,这种函数描述了特定的运算符与类之间的关系。 运算符函数可以是类成员函数,也可以是友元函数(有一些运算符函数只能是类成员函数)。要调用运算符函数, 可以直接调用该函数,也可以以通常的句法使用被重载的运算符。对于运算符op,其运算符函数的格式如下;
operatorop (argument-list)
argument -list 表示该运算符的操作数。如果运算符函数是类成员函数,则第一个操作数是调用对象, 它 不 在 a r g u m e n t - l i s t 中 。 例 如 , 本 章 通 过 为 V e c t o r 类 定 义 o p e r a t o r + ( )成 员 函 数 重 载 了 加 法 。 如 果 u p 、 r i g h t 和result 都是Vector 对象,则可以使用下面的任何 一条语句来调用矢量加法:
result = up.operator+ (right) ; result = up + right;
在第二条语句中,由于操作数up和right的类型都是Vect or,因此C++将使用Vector的加法定义。 当运算符函数是成员函数时,则第一个操作数将是调用该函数的对象 。例如 ,在前面的语句中,up对 象是调用函数的对象。定义运算符函数时,如果要使其第一个操作数不是类对象,则必须使用友元函数。 这样就可以将操作数按所需的顺序传递给函数了。
最常?的运算符重载任务之 一是定义< 运算符,使之可与cout 一起使用,来显示对象的内容。要让 ostream 对象成为第一个操作数,需要将运算符函数定义为友元:要使重新定义的运算符能与其自身拼接, 需要将返回类型声明为ostream&。下面的通用格式能够满足这种要求:
ostream & operator??(ostream &os, const c_name &obj) {
? ?os ? . . . ; / display object contents
? return os;
}
然而,如果类包含这样的方法,它返回需要显示的数据成员的值,则 可以使用这些方法,无需在 operator<<()中直接访问这些成员 。在这种情况下,函数不必(也不应当)是友元。 C++允许指定在类和基本类型之间进行转换的方式。首先,任何接受唯一 一个参数的构造函数都可被 用作转换函数,将类型与该参数相同的值转换为类。如果将类型与该参数相同的值赋给对象,则C++将自 动调用该构造函数。例如,假设有一个String类,它包含一个将char *值作为其唯一参数的构造函数,那 么 如 果 b e a n 是 S t r i n g 对 象 , 则 可 以 使 用 下面 的 语 句 :
bean = "pinto"; // converts type char * to type String
然 而 , 如 果 在 该 构 造 函 数 的 声 明 前 加 上 了 关键 字 e x p l i c i t , 则 该 构 造 函 数 将 只 能 用 于显 式 转 换 :
bean = String ("pinto"); // converts type char * to type String explicitly
要将类对象转换为其他类型,必须定义转换函数,指出如何进行这种转换。转换函数必须是成员函数。 将类对象转换为typeName类型的转换函数的原型如下:
operator typeName();
注意,转换函数没有返回类型、没有参数 ,但必须返回转换后的值(虽然没有声明返回类型)。例如, 下面 是 将 V e c t o r 转 换 为 d o u b l e 类 型 的 函 数 :
Vector: :operator double()
{
...
return a_double_value;
}
经验表明,最好不要依赖于这种隐式转换函数。