C++ 全局运算符和成员运算符的区别

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1145022/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 19:01:23  来源:igfitidea点击:

difference between global operator and member operator

c++operator-overloading

提问by Vargas

Is there a difference between defining a global operator that takes two references for a class and defining a member operator that takes only the right operand?

定义一个接受类的两个引用的全局运算符和定义一个只接受正确操作数的成员运算符之间有区别吗?

Global:

全球的:

class X
{
public:
    int value;
};

bool operator==(X& left, X& right) 
{
    return left.value == right.value;
};

Member:

成员:

class X
{
    int value;
    bool operator==( X& right) 
    {
        return value == right.value;
    };
}

回答by Tim Sylvester

One reason to use non-member operators (typically declared as friends) is because the left-hand side is the one that does the operation. Obj::operator+is fine for:

使用非成员运算符(通常声明为友元)的一个原因是因为左侧是执行操作的运算符。 Obj::operator+适合:

obj + 2

but for:

但对于:

2 + obj

it won't work. For this, you need something like:

它不会工作。为此,您需要类似的东西:

class Obj
{
    friend Obj operator+(const Obj& lhs, int i);
    friend Obj operator+(int i, const Obj& rhs);
};

Obj operator+(const Obj& lhs, int i) { ... }
Obj operator+(int i, const Obj& rhs) { ... }

回答by Drew Dormann

Your smartest option is to make it a friend function.

最明智的选择是将其设为友元函数

As JaredPar mentions, the global implementation cannot access protected and private class members, but there's a problem with the member function too.

正如 JaredPar 所提到的,全局实现无法访问 protected 和 private 类成员,但成员函数也存在问题。

C++ will allow implicit conversions of function parameters, but not an implicit conversion of this.

C++ 将允许隐式转换函数参数,但不允许隐式转换this.

If types exist that can be converted to your X class:

如果存在可以转换为 X 类的类型:

class Y
{
public:
    operator X();  // Y objects may be converted to X
};


X x1, x2;
Y y1, y2;

Only some of the following expressions will compile with a member function.

只有以下一些表达式会与成员函数一起编译。

x1 == x2;   // Compiles with both implementations
x1 == y1;   // Compiles with both implementations
y1 == x1;   // ERROR!  Member function can't convert this to type X
y1 == y2;   // ERROR!  Member function can't convert this to type X

The solution, to get the best of both worlds, is to implement this as a friend:

为了两全其美,解决方案是将其作为朋友实施:

class X
{
    int value;

public:

    friend bool operator==( X& left, X& right ) 
    {
        return left.value == right.value;
    };
};

回答by David Rodríguez - dribeas

To sum up to the answer by Codebender:

总结 Codebender 的回答:

Member operators are not symmetric. The compiler cannot perform the same number of operations with the left and right hand side operators.

成员运算符不是对称的。编译器无法使用左侧和右侧运算符执行相同数量的操作。

struct Example
{
   Example( int value = 0 ) : value( value ) {}
   int value;

   Example operator+( Example const & rhs ); // option 1
};
Example operator+( Example const & lhs, Example const & rhs ); // option 2
int main()
{
   Example a( 10 );
   Example b = 10 + a;
}

In the code above will fail to compile if the operator is a member function while it will work as expected if the operator is a free function.

在上面的代码中,如果运算符是成员函数,则编译失败,而如果运算符是自由函数,它将按预期工作。

In general a common pattern is implementing the operators that must be member functions as members and the rest as free functions that delegate on the member operators:

一般来说,一个常见的模式是将必须是成员函数的运算符实现为成员,而其余的则作为委托成员运算符的自由函数实现:

class X
{
public:
   X& operator+=( X const & rhs );
};
X operator+( X lhs, X const & rhs )
{
   lhs += rhs; // lhs was passed by value so it is a copy
   return lhs;
}

回答by JaredPar

There is at least one difference. A member operator is subject to access modifiers and can be public, protected or private. A global member variable is not subject to access modifier restrictions.

至少有一个区别。成员运算符受访问修饰符的约束,可以是公共的、受保护的或私有的。全局成员变量不受访问修饰符限制。

This is particularly helpful when you want to disable certain operators like assignment

当您想禁用某些运算符(如赋值)时,这特别有用

class Foo { 
  ...
private:
  Foo& operator=(const Foo&); 
};

You could achieve the same effect by having a declared only global operator. But it would result in a link error vs. a compile error (nipick: yes it would result in a link error within Foo)

您可以通过声明唯一的全局运算符来实现相同的效果。但它会导致链接错误与编译错误(nipick:是的,它会导致 Foo 中的链接错误)

回答by riv

Here's a real example where the difference isn't obvious:

这是一个真实的例子,其中差异并不明显:

class Base
{
public:
    bool operator==( const Base& other ) const
    {
        return true;
    }
};

class Derived : public Base
{
public:
    bool operator==( const Derived& other ) const
    {
        return true;
    }
};

Base() == Derived(); // works
Derived() == Base(); // error

This is because the first form uses equality operator from base class, which can convert its right hand side to Base. But the derived class equality operator can't do the opposite, hence the error.

这是因为第一种形式使用来自基类的相等运算符,它可以将其右侧转换为Base. 但是派生类相等运算符不能做相反的事情,因此错误。

If the operator for the base class was declared as a global function instead, both examples would work (not having an equality operator in derived class would also fix the issue, but sometimes it is needed).

如果基类的运算符被声明为全局函数,则两个示例都可以工作(派生类中没有相等运算符也可以解决问题,但有时需要)。