我在标题中看到我没有写下以下内容:
class MonitorObjectString: public MonitorObject {
// some other declarations
friend inline bool operator==(MonitorObjectString& lhs, MonitorObjectString& rhs) { return(lhs.fVal==rhs.fVal); }
我无法理解为什么这个方法被声明为朋友。我认为如果函数在另一个地方定义并且需要访问类的内部成员是有意义的,但这不是这里的情况,因为它是内联的,甚至不需要访问成员。 / p> 你怎么看?这位“朋友”没用吗?
答案 0 :(得分:36)
friend inline bool operator==(MonitorObjectString& lhs, MonitorObjectString& rhs) {
return(lhs.fVal==rhs.fVal);
}
称为friend definition
。它将函数定义为它所出现的类所围绕的命名空间的非成员函数。实际上,内联存在冗余:如果它是朋友定义,则隐式声明内联。它的一些优点和缺点:
MonitorObjectString
的内部。但这既不好也不坏。这取决于实际情况。例如,如果有函数getFVal()
使得函数朋友毫无意义。那么可以使用getFVal
。 我曾经喜欢这种朋友定义的运算符风格,因为他们可以直接访问类成员,并且出现在类定义中 - 所以我可以拥有“一见钟情”。然而,最近我得出的结论是,这并不总是一个好主意。如果你可以(并且你应该)纯粹使用类的公共成员函数来实现运算符,则应该使它成为在类的同一名称空间中定义的非朋友(和非成员)运算符。它确保如果您更改某些实现 - 但保持类的接口相同 - 操作员仍然可以工作,并且您的级联更改较少,因为您知道它无法访问实现细节。
然而,我更喜欢这种风格而不是编写成员运算符,因为命名空间范围内的运算符函数具有与其参数对称的附加功能:它们不会将左侧特殊处理,因为两者都是sides只是普通参数,而不是绑定到*this
的对象参数。如果左侧或右侧属于您的类的类型,则可以隐式转换另一侧 - 无论是左侧还是右侧。对于也没有友元定义语法(传统上,在命名空间范围内)定义的函数,您将具有选择性地包括使这些运算符可用或不可用的标头的功能。
答案 1 :(得分:7)
语法上说......
仍然需要friend
关键字来告诉编译器该函数不是类的成员,编辑:而是可以看到私有成员的非成员函数该课程。
然而,这可以更加干净地实施:
/* friend */ inline bool operator ==(const MonitorObjectString& rhs) const
{ return fVal == rhs.fVal; }
(当然,我假设fVal
是一个合适的类型,可以在不影响其常数的情况下进行比较。)
答案 2 :(得分:7)
它们不是相互排斥的。 “friend”表示非成员函数可以访问该类的私有成员。 “inline”表示没有函数调用调用,函数体在每个调用站点都是重复的(在汇编中)。