friend inline bool operator==(MonitorObjectString& lhs, MonitorObjectString& rhs) {
return(lhs.fVal==rhs.fVal);
}
有时称为friend definition
,因为它是定义函数的友元声明。它将函数定义为围绕它出现的类的命名空间的非成员函数。实际上,那里的内联是多余的:如果它是友元定义,则它被隐式声明为内联。它的一些优点和缺点:
- 它使操作符对正常查找不可见。您可以调用它的唯一方法是使用参数相关查找。这将使命名空间没有大量正常可见的运算符声明。请注意,这还将禁用使用隐式转换为 MonitorObjectString 调用它的能力(因为如果在查找要调用的候选者时两种参数类型不匹配,则依赖于参数的查找将找不到该函数)。
- 名称的查找始于友元定义所在的类的范围。这意味着不需要写出长类型名称或其他名称。只需像在类的普通成员函数中那样引用它们即可。
- 因为它是一个朋友,所以该函数可以看到
MonitorObjectString
. 但这既不好也不坏。这取决于实际情况。例如,如果有功能getFVal()
使功能成为朋友是毫无意义的。那时也可以使用getFVal
。
我曾经喜欢这种操作符的朋友定义风格,因为它们可以直接访问类成员,并且出现在类定义中——所以我可以“一目了然”。然而,最近我得出的结论是,这并不总是一个好主意。如果您可以(并且应该)纯粹使用类的公共成员函数来实现运算符,则应该将其设为非友元(和非成员)运算符,定义在类的同一命名空间中。它确保如果您更改某些实现 - 但保持类的接口相同 - 运算符仍然可以工作并且您的级联更改更少,因为您知道它无法访问实现细节。
但是,我更喜欢这种风格而不是编写成员运算符,因为命名空间范围内的运算符函数具有与参数对称的附加特性:它们不会将左侧特殊对待,因为两侧只是普通参数而不是对象参数必然*this
。如果左侧或右侧属于您的类的类型,则可以隐式转换另一侧 - 无论它是左侧还是右侧。对于同样在没有友元定义语法的情况下定义的函数(传统上,在命名空间范围内),您将具有选择性地包含使这些运算符可用或不可用的标头的功能。