使用friend
关键字的运算符重载和作为类中的成员函数有什么区别?
此外,任何一元运算符重载(即作为朋友与成员函数)的情况有何不同?
答案 0 :(得分:12)
Jacob是正确的......在类中声明的friend
函数可以访问该类,但它根本不在类中,其他人都可以访问它。
对于不是类成员的运算符重载(也称为自由函数,它可能是朋友,或者可能不是),参数与操作数相同。对于作为类成员的一个,第一个操作数是“隐含参数”,它变为this
。
隐式参数在几个方面与自由函数的第一个参数不同:
virtual
重载将由第一个操作数的动态类型选择,这对于没有额外代码的自由函数是不可能的。)一元,二元或一元的情况是相同的(在operator()
的情况下)。
成员突变特权:更改第一个操作数的运算符(例如+=
,=
,前缀++
)应该实现为成员函数,并且应该专门实现所有重载的内容。 Postfix ++
是二等公民;它实现为Obj ret = *this; ++ this; return ret;
。请注意,这有时会扩展到copy-constructors,它可能包含*this = initializer
。
通勤者的自由规则:只有交换运营商(例如/
)应该是自由职能;所有其他运营商(例如一元一事)应该是成员。交换运算符固有地制作对象的副本;它们被实现为Obj ret = lhs; ret @= rhs; return ret;
,其中@
是可交换运算符,lhs
和rhs
分别是左侧和右侧参数。
C ++友谊的黄金法则:避免友谊。 friend
污染了设计的语义。 重载推论:如果您遵循上述规则,重载很简单,那么friend
是无害的。 friend
样板过载定义允许将它们放在class {
括号内。
请注意,某些运算符不能是自由函数:=
,->
,[]
和()
,因为标准在第13.5节中明确说明了这一点。我认为这就是全部...我认为一元&
和*
也是如此,但我显然是错的。但是,应总是作为成员超载,并且只有经过深思熟虑后才会过载!
答案 1 :(得分:3)
不同之处在于,friended函数实际上处于全局范围内,因此您无需成为该类的实例即可访问它。
答案 2 :(得分:1)
成员函数要求左手操作符必须属于该类型。 友元函数可以允许左手操作符隐式转换。
例如,假设我们创建了一个BigInt类。我们创建了一个成员函数operator +来获取BigInt的右手操作符。
现在让我们也说BigInt有一个带有常规int的构造函数。此构造函数不是显式的(显式关键字),它需要一个参数。这意味着C ++可以从int转换为BigInt。
当我们有这些东西时,我们可以这样做:
BigInt foo(5); BigInt酒吧; bar = foo + 5;
但我们不能这样做:
BigInt foo(5) BigInt酒吧; bar = 5 + foo;
但是,如果我们使用友元函数而不是成员函数,那么两者都可以工作。
答案 3 :(得分:1)
成员函数要求左手操作符必须属于该类型。友元函数可以允许左手操作符隐式转换。
答案 4 :(得分:0)
可以在rvalues上调用成员函数,而不能使用rvalues调用接受对非const的引用的自由函数。例如,++function_returning_iterator_by_value()
仅在您将operator++
作为成员实施时进行编译。