朋友和内联方法,有啥意义?
Posted
技术标签:
【中文标题】朋友和内联方法,有啥意义?【英文标题】:friend AND inline method, what's the point ?朋友和内联方法,有什么意义? 【发布时间】:2010-09-27 17:25:44 【问题描述】:我在标题中看到我没有给自己写以下内容:
class MonitorObjectString: public MonitorObject
// some other declarations
friend inline bool operator==(MonitorObjectString& lhs, MonitorObjectString& rhs) return(lhs.fVal==rhs.fVal);
我不明白为什么这个方法被声明为朋友。我认为如果函数在另一个地方定义并且需要访问类的内部成员,这将是有意义的,但这里不是这种情况,因为它是内联的,甚至不需要访问成员。
你怎么看? “朋友”没用吗?
【问题讨论】:
【参考方案1】:从语法上讲...
friend
关键字仍然需要告诉编译器这个函数不是一个类的成员,编辑:而是一个可以看到私有成员的非成员函数类。
但是,这可以像这样更干净地实现:
/* friend */ inline bool operator ==(const MonitorObjectString& rhs) const
return fVal == rhs.fVal;
(当然,我假设fVal
是一个合适的类型,可以在不影响其常量性的情况下进行比较。)
【讨论】:
这里不需要朋友? 结果类似;但一般来说,非修改运算符应该更喜欢非成员,因为如果运算符是成员函数,编译器无法将左侧类型转换为类类型;而它可以使用非成员函数。 您的“更干净”的解决方案被许多人认为是糟糕的设计。如果我创建一个可以隐式转换为“MonitorObjectString”的“ShmooptyString”,则代码 MOS==SS 将编译,但 SS==MOS 不会。问题是参数允许隐式转换,但您不能隐式转换“this” 我忘记了一些事情:当被比较的对象没有值语义时,重载运算符 == 没有意义。继承没有意义。 Eduardo,如何“更干净”?它具有相同的私有成员访问权限并已成为成员。所以它有更强的耦合,这更糟。朋友的定义会更干净恕我直言。【参考方案2】:它们不是相互排斥的。 “朋友”表示非成员函数可以访问类的私有成员。 “内联”意味着没有函数调用调用,函数的主体在每个调用点都被复制(在汇编中)。
【讨论】:
好吧,我明白了。但是既然这个方法是类的成员,为什么要声明它为朋友呢? 如果是朋友,则不是班级成员。 @Barth - Eduardo 是正确的。如果你把朋友放在函数前面,它就是独立的!不是方法。这就是为什么它需要两个!参数,没有隐含的“this”。 关键字'inline'并不意味着它实际上是内联代码。这是对编译器的“提示”。只有在有意义的情况下,编译器才会内联。 但无论如何,“内联”具有效果。这不是没用的。它将为 ODR 提供一些特别有用的前提。无论如何,这里的内联 是多余的,因为在友元定义中定义的函数是隐式内联的【参考方案3】:friend inline bool operator==(MonitorObjectString& lhs, MonitorObjectString& rhs)
return(lhs.fVal==rhs.fVal);
有时称为friend definition
,因为它是一个定义函数的友元声明。它将函数定义为围绕它出现的类的命名空间的非成员函数。实际上,内联是多余的:如果它是友元定义,则隐式声明内联。它的一些优点和缺点:
MonitorObjectString
的内部。但这既不好也不坏。这取决于实际情况。例如,如果有函数 getFVal()
让函数成为朋友是毫无意义的。也可以使用getFVal
。
我曾经喜欢这种朋友定义风格的运算符,因为它们可以直接访问类成员,并且出现在类定义中——所以我可以“一目了然”。然而,最近我得出的结论是,这并不总是一个好主意。如果您可以(并且应该)纯粹使用类的公共成员函数来实现该运算符,则应该将其设为非友元(和非成员)运算符,定义在该类的同一命名空间中。它确保如果您更改某些实现 - 但保持类的接口相同 - 运算符仍然可以工作,并且您的级联更改更少,因为您知道它无法访问实现细节。
然而,我更喜欢这种风格而不是编写成员运算符,因为命名空间范围内的运算符函数具有与参数对称的附加特性:它们不会将左侧特殊对待,因为两者边只是普通参数,而不是绑定到*this
的对象参数。如果左侧或右侧属于您的类的类型,则可以隐式转换另一侧 - 无论它是左侧还是右侧。对于同样在没有友元定义语法的情况下定义的函数(传统上,在命名空间范围内),您将具有选择性地包含使这些运算符可用或不可用的标头的功能。
【讨论】:
"如果是友元定义,则隐式声明为内联。"这是不正确的。就像成员函数一样,如果在类主体之外定义非成员友元函数,则不会隐式声明为内联。 @JMC 我指的是朋友的定义。不是没有friend关键字的定义(即在类之外)。 在这种情况下,您当然是正确的。我理解术语“朋友定义”包括碰巧是朋友的函数的任何定义。尽管如此,它听起来好像它的朋友是决定因素,我宁愿说:它被隐式声明为内联,因为朋友定义只能出现在类体内,这使得它们在任何情况下都是内联的。 @JMC 为什么没有同样的问题? “朋友定义只能出现在类体内”在您的解释下是错误的。至于歧义,我认为我最初的句子“......被称为朋友定义。它......”已经足够清楚了。但似乎“朋友定义”不是官方术语(我是通过将“朋友声明”与“A声明也是定义如果......”规则相结合来构建它),所以我会补充说明。 @JMC 我同意如果函数不是内联的那将是非常愚蠢的。但是对于作为定义的友元函数声明,实际上有一个明确的规则,即它们是隐式内联的。所以我感觉更好地反映这种明确的依赖关系,而不是依赖“类内”的东西。以上是关于朋友和内联方法,有啥意义?的主要内容,如果未能解决你的问题,请参考以下文章