简体   繁体   English

为什么某些运算符只能作为成员函数重载,其他作为友元函数,其余的作为两者?

[英]Why can some operators only be overloaded as member functions, other as friend functions and the rest of them as both?

Why can some operators only be overloaded as member functions, other as non-member "free" functions and the rest of them as both? 为什么某些运算符只能作为成员函数重载,其他作为非成员“自由”函数,其余的作为两者?

What is the rationale behind those? 这些背后的理由是什么?

How to remember which operators can be overloaded as what (member, free, or both)? 如何记住哪些运营商可以超载(成员,免费或两者)?

The question lists three classes of operators. 该问题列出了三类运算符。 Putting them together on a list helps, I think, with understanding why a few operators are restricted in where they can be overloaded: 将它们放在一个列表中有助于我理解为什么一些运算符在可以重载的位置受到限制:

  1. Operators which have to be overloaded as members. 必须作为成员超载的运营商。 These are fairly few: 这些相当少:

    1. The assignment operator=() . 赋值operator=() Allowing non-member assignments seems to open the door for operators hijacking assignments, eg, by overloading for different versions of const qualifications. 允许非成员分配似乎为操作员劫持任务打开了大门,例如,通过重载不同版本的const资格。 Given that assignment operators are rather fundamental that seems to be undesirable. 鉴于赋值运算符相当基础,似乎是不合需要的。
    2. The function call operator()() . 函数调用operator()() The function call and overloading rules are sufficiently complicated as is. 函数调用和重载规则足够复杂。 It seems ill-advised to complicate the rules further by allowing non-member function call operators. 通过允许非成员函数调用操作符来进一步使规则复杂化似乎是不明智的。
    3. The subscript operator[]() . 下标operator[]() Using interesting index types it seems that could interfere with accesses to operators. 使用有趣的索引类型似乎可能会干扰对运营商的访问。 Although there is little danger of hijacking overloads, there doesn't seem to be much gain but interesting potential to write highly non-obvious code. 虽然劫持重载几乎没有什么危险,但似乎没有太大的收获,但有可能编写高度非显而易见的代码。
    4. The class member access operator->() . 类成员访问operator->() Off-hand I can't see any bad abuse of overloading this operator a non-member. 副手我看不到任何重载此操作员非成员的不良滥用。 On the other hand, I also can't see any. 另一方面,我也看不到任何。 Also, the class member access operator has rather special rules and playing with potential overloads interfering with these seems an unnecessary complication. 此外,类成员访问操作符具有相当特殊的规则,并且使用潜在的重载来干扰这些似乎是不必要的复杂化。

    Although it is conceivable to overload each of these members are a non-member (especially the subscript operator which is works on arrays/pointers and these can be on either side of the call) it seems surprising if, eg, an assignment could be hijacked by a non-member overload which which is a better match than one of the member assignments. 尽管可以想象重载这些成员中的每一个都是非成员(特别是下标运算符,它可以在数组/指针上运行,并且这些可以在调用的任何一侧)但是,如果例如一个赋值可能被劫持,这似乎是令人惊讶的。通过非成员重载,这是一个比成员分配更好的匹配。 These operators are also rather asymmetric: you generally wouldn't want to support conversion on both sides of an expression involving these operators. 这些运算符也相当不对称:您通常不希望支持涉及这些运算符的表达式两侧的转换。

    That said, eg, for a lambda expression library it would be nice if it were possible to overload all of these operators and I don't think there is an inherent technical reason to preventing these operators from being overloadable. 也就是说,例如,对于一个lambda表达式库,如果可以重载所有这些运算符会很好,我不认为有一个固有的技术原因可以防止这些运算符过载。

  2. Operators which have to be overloaded as non-member functions. 必须作为非成员函数重载的运算符。

    1. The user-defined literal operator"" name() 用户定义的文字operator"" name()

    This operator is somewhat of an odd-ball and, arguably not really really an operator. 这个算子有点像一个奇怪的球,可能并不是真正的算子。 In any case, there is no object to call this member on for which members could be defined: the left argument of user-defined literals are always built-in types. 在任何情况下,没有对象可以调用此成员来定义成员:用户定义的文字的左参数始终是内置类型。

  3. Not mentioned in the question but there are also operator which can't be overloaded at all: 在问题中没有提到,但也有一些运算符根本不能超载:

    1. The member selector . 成员选择器.
    2. The pointer-to-member object access operator .* 指向成员的对象访问运算符.*
    3. The scope operator :: 范围运营商::
    4. The ternary operator ?: 三元运算符?:

    These four operators were considered to be too fundamental to be meddled with at all. 这四个运营商被认为太根本,根本无法干预。 Although there was a proposal to allow overloading operator.() at some point there isn't strong support doing so (the main use case would be smart references). 虽然有一个提议允许重载operator.()在某些时候没有强有力的支持这样做(主要的用例是智能引用)。 Although there are certainly some contexts imaginable where it would be nice to overload these operators, too. 虽然确实存在一些可以想象的环境,但是这些运算符也会过载。

  4. Operators which can be overloaded either as members or as non-members. 可以作为成员或非成员超载的运营商。 This is the bulk of the operators: 这是大部分运营商:

    1. The pre- and post-increment/-decrement operator++() , operator--() , operator++(int) , operator--(int) 前后增量/ -decrement operator++()operator--()operator++(int)operator--(int)
    2. The [unary] dereference operator*() [一元]解除引用operator*()
    3. The [unary] address-of operator&() [一元]地址 - operator&()
    4. The [unary] signs operator+() , operator-() [一元]符号operator+()operator-()
    5. The logical negation operator!() (or operator not() ) 逻辑否定operator!() (或operator not()
    6. The bitwise inversion operator~() (or operator compl() ) 按位反转operator~() (或operator compl()
    7. The comparisons operator==() , operator!=() , operator<() , operator>() , operator<=() , and operator>() 比较operator==()operator!=()operator<()operator>()operator<=()operator>()
    8. The [binary] arithmetic operator+() , operator-() , operator*() , operator/() , operator%() [二进制]算术运算operator+()operator-()operator*()operator/()operator%()
    9. The [binary] bitwise operator&() (or operator bitand() ), operator|() (or operator bit_or() ), operator^() (or operator xor() ) [binary]按位运算operator&() (或operator bitand() ), operator|() (或operator bit_or() ), operator^() (或operator xor()
    10. The bitwise shift operator<<() and operator>>() 按位移位运算operator<<()operator>>()
    11. The logic operator||() (or operator or() ) and operator&&() (or operator and() ) 逻辑operator||() (或operator or() )和operator&&() (或operator and()
    12. The operation/assignment operator@=() (for @ being a suitable operator symbol() 操作/赋值operator@=() (对于@是一个合适的运算符符号()
    13. The sequence operator,() (for which overloading actually kills the sequence property!) 序列operator,() (重载实际上会杀死序列属性!)
    14. The pointer pointer-to-member access operator->*() 指针指向成员访问operator->*()
    15. The memory management operator new() , operator new[]() , operator new[]() , and operator delete[]() 内存管理operator new()operator new[]()operator new[]()operator delete[]()

    The operators which can be overloaded either as members or as non-members are not as necessary for fundamental object maintenance as the other operators. 作为成员或非成员可能过载的操作员不像其他操作员那样进行基本对象维护。 That is not to say that they are not important. 这并不是说它们并不重要。 In fact, this list contains a few operators where it is rather questionable whether they should be overloadable (eg, the address-of operator&() or the operators which normally cause sequencing, ie, operator,() , operator||() , and operator&&() . 事实上,这个列表包含一些运算符,它们是否应该是可重载的(例如, operator&()地址operator&()或通常导致排序的运算符,即operator,()operator||() ,和operator&&()

Of course, the C++ standard doesn't give a rationale on why things are done the way they are done (and there are also no records of the early days when these decisions where made). 当然,C ++标准没有给出为什么事情按照完成方式完成的理由(并且也没有关于这些决策所在的早期记录)。 The best rationale can probably be found in "Design and Evolution of C++" by Bjarne Stroustrup. 最好的理由可以在Bjarne Stroustrup的“C ++的设计和演变”中找到。 I recall that the operators were discussed there but there doesn't seem to be an electronic version available. 我记得在那里讨论过运营商,但似乎没有可用的电子版本。

Overall, I don't think there are really strong reasons for the restrictions other than potential complication which was mostly not considered worth the effort. 总的来说,除了潜在的并发症之外,我认为除了潜在的并发症之外,还有其他限制措施的确有很强的理由。 I would, however, doubt that the restrictions are likely to be lifted as the interactions with existing software are bound to change the meaning of some program in unpredictable ways. 但是,我怀疑这些限制可能会被解除,因为与现有软件的交互必然会以不可预测的方式改变某些程序的含义。

The rationale is that it would not make sense for them to be non-members, as the thing on the left-hand side of the operator must be a class instance. 理由是它们不是非成员是没有意义的,因为运算符左侧的东西必须是类实例。

For example, assuming a class A 例如,假设一个A类

A a1;
..
a1 = 42;

The last statement is really a call like this: 最后一个语句实际上是这样的调用:

a1.operator=(42);

It would not make sense for the thing on the LHS of the . 对LHS的事情没有意义 not to be an instance of A, and so the function must be a member. 不要成为A的实例,因此该函数必须是成员。

Because you can't modify the semantics of primitive types. 因为您无法修改基本类型的语义。 It wouldn't make sense to define how operator= works on an int , how to deference a pointer, or how an array access works. 定义operator=如何在int ,如何引用指针或数组访问如何工作是没有意义的。

Here is one example: When you are overloading the << operator for a class T the signature will be: 这是一个例子:当您为class T重载<< operator ,签名将是:

std::ostream operator<<(std::ostream& os, T& objT )

where the implementation needs to be 实施需要的地方

{
//write objT to the os
return os;
}

For the << operator the first argument needs to be the ostream object and the second argument your class T object. 对于<<运算符,第一个参数需要是ostream对象,第二个参数需要是类T对象。

If you try to define operator<< as a member function you will not be allowed to define it as std::ostream operator<<(std::ostream& os, T& objT) . 如果您尝试将operator<<定义为成员函数,则不允许将其定义为std::ostream operator<<(std::ostream& os, T& objT) This is because binary operator member functions can only take one argument and the invoking object is implicitly passed in as the first argument using this . 这是因为二元运算符成员函数只能接受一个参数,并且使用this作为第一个参数隐式传入调用对象。

If you use the std::ostream operator<<(std::ostream& os) signature as a member function you will actually end up with a member function std::ostream operator<<(this, std::ostream& os) which will not do what you want. 如果你使用std::ostream operator<<(std::ostream& os)签名作为成员函数,你实际上最终会得到一个成员函数std::ostream operator<<(this, std::ostream& os)不要做你想要的。 Therefore you need a operator that is not a member function and can access member data (if your class T has private data you want to stream, operator<< needs to be a friend of class T). 因此,您需要一个不是成员函数的运算符,并且可以访问成员数据(如果您的类T具有要传输的私有数据,则operator<<需要是T类的朋友)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 为什么重载复合赋值运算符可以是非成员函数? - Why can overloaded compound assignment operators be non-member functions? 为什么歧义只适用于重载运算符而不适用于具有“相同”名称但不同 scope 的函数? - Why ambiguity only for overloaded operators and not for functions with "same" name but different scope? 成员函数vs朋友函数:为什么一个而不是另一个? - Member function vs friend functions: why one and not the other? 运算符重载函数作为朋友? - Operator overloaded functions as friend? 哪些运算符只能声明为非静态成员函数? - Which operators can only be declared as non-static member functions? 在c ++中只有静态成员函数的朋友类作为朋友模块? - Friend class with only static member functions as a friend module in c++? 移动仅由一个其他成员函数使用的成员函数并使其成为本地函数时的性能考虑因素? - performance considerations when moving member functions that are used only by one other member function and making them local functions? 具有重载成员函数的多线程 - Multithreading with overloaded member functions C ++朋友类和朋友成员函数 - C++ friend classes and friend member functions 确定重载成员函数的签名 - Determine signatures of overloaded member functions
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM