运算符重载(友元和成员函数)
使用 friend
关键字进行运算符重载与作为类内的成员函数进行运算符重载有什么区别?
另外,在任何一元运算符重载的情况下(即作为友元与作为成员函数)有什么区别?
What is the difference between operator overloading using the friend
keyword and as a member function inside a class?
Also, what is the difference in the case of any unary operator overloading (i.e. as a friend vs. as a member function)?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
成员函数要求左侧运算符必须是该类型。友元函数可以允许对左侧运算符进行隐式转换。
A member function requires that the left hand operator must be of that type. A friend function can allow implicit casting on the left hand operator.
可以对右值调用成员函数,而不能用右值调用接受非常量引用的自由函数。例如,仅当您将
operator++
实现为成员时,++function_returning_iterator_by_value()
才会编译。Member functions can be called on rvalues, whereas free functions accepting references to non-const cannot be called with rvalues. For example,
++function_returning_iterator_by_value()
only compiles if you implementoperator++
as a member.Jacob 是正确的……在类中声明的
friend
函数可以访问该类,但它根本不在类内部,而其他人都可以访问它。对于不是类成员的运算符重载(也称为自由函数,它可能是友元,也可能不是),参数与操作数相同。对于类的成员,第一个操作数是“隐式参数”,它变为
this
。隐式参数与自由函数的第一个参数在几个方面有所不同:
一元、二进制或 n 元的情况是相同的(对于
operator()
)。成员变异特权:更改第一个操作数的运算符(例如
+=
、=
、前缀++
)应该作为成员函数实现,并且应该专门实现所有重载的核心。 Postfix++
是二等公民;它的实现为 Obj ret = *this; ++ 这个;返回ret;。请注意,这有时会扩展到复制构造函数,其中可能包含 *this = 初始值设定项。通勤者的自由规则:只有可交换运算符(例如
/
)才应该是自由函数;所有其他运算符(例如一元运算符)都应该是成员。交换运算符本质上会复制对象;它们被实现为 Obj ret = lhs; ret@=rhs; return ret; 其中@
是交换运算符,lhs
和rhs
是左侧和右侧参数,分别。C++ 友谊的黄金法则:避免友谊。
friend
污染了设计的语义。 重载推论:如果遵循上述规则,重载很简单,那么friend
是无害的。样板重载定义的交友允许将它们放置在 class { 大括号内。请注意,某些运算符不能是自由函数:
=
、->
、[]
和()
,因为该标准在第 13.5 节中有明确规定。我认为这就是全部......我认为一元&
和*
也是如此,但我显然错了。不过,他们应该始终作为成员超载,而且只有在仔细考虑之后!Jacob is correct… a
friend
function declared within a class has access to that class, but it's not inside the class at all, and everyone else has access to it.For an operator overload which is not a member of the class (also called a free function, it may be a friend, or maybe not), the arguments are the same as the operands. For one which is a member of a class, the first operand is the "implicit argument" which becomes
this
.The implicit argument is different from the first argument to a free function in a few ways:
virtual
overload will be chosen by the dynamic type of the first operand, which is not possible with free functions without extra code.)The situation is the same for unary, binary, or n-ary (in the case of
operator()
).Members privilege of mutation: Operators which change the first operand (eg
+=
,=
, prefix++
) should be implemented as member functions, and should exclusively implement the guts of all overloads. Postfix++
is a second-class citizen; it is implemented asObj ret = *this; ++ this; return ret;
. Note that this sometimes extends to copy-constructors, which may contain*this = initializer
.Rule of freedom for commuters: Only commutative operators (eg
/
) should be free functions; all other operators (eg unary anything) should be members. Commutative operators inherently make a copy of the object; they are implemented asObj ret = lhs; ret @= rhs; return ret;
where@
is the commutative operator andlhs
andrhs
are left-hand side and right-hand side arguments, respectively.Golden rule of C++ friendship: Avoid friendship.
friend
pollutes the semantics of a design. Overloading corollary: Overloading is simple if you follow the above rules, thenfriend
is harmless.friend
ing boilerplate overload definitions allows them to be placed inside theclass {
braces.Note that some operators cannot be free functions:
=
,->
,[]
, and()
, because the standard specifically says so in section 13.5. I think that's all… I thought unary&
and*
were too, but I was apparently wrong. They should always be overloaded as members, though, and only after careful thought!不同之处在于友元函数实际上位于全局范围内,因此您不需要成为该类的实例即可访问它。
The difference is that the friended function is actually in global scope, so you do not need to be an instance of the class to have access to it.
成员函数要求左侧运算符必须是该类型。
友元函数可以允许对左侧运算符进行隐式转换。
例如,假设我们创建一个 BigInt 类。我们创建一个成员函数operator + 来获取BigInt 的右手运算符。
现在我们还可以说 BigInt 有一个采用常规 int 的构造函数。该构造函数不是显式的(显式关键字),并且它采用一个参数。这意味着 C++ 可以隐式地从 int 转换为 BigInt。
当我们拥有这些东西时,我们可以这样做:
BigInt foo( 5 );
BigInt 条;
酒吧 = 富 + 5;
但我们不能这样做:
BigInt foo( 5 )
BigInt 条;
酒吧= 5 + 富;
但是,如果我们使用友元函数而不是成员函数,那么两者都可以工作。
A member function requires that the left hand operator must be of that type.
A friend function can allow implicit casting on the left hand operator.
So for example, lets say we create a BigInt class. And we create a member function operator + to take a right hand operator of BigInt.
Now lets also say BigInt has a constructor that takes a regular int. This constructor is NOT explicit (explicit keyword) and it takes one parameter. That means C++ can implitily convert from int to BigInt.
When we have these things we can do this:
BigInt foo( 5 );
BigInt bar;
bar = foo + 5;
But we CAN'T do this:
BigInt foo( 5 )
BigInt bar;
bar = 5 + foo;
However, if we used a friend function instead of a member function then both will work.