全局运营商和成员运营商之间的差异

Var*_*gas 39 c++ operator-overloading

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

全球:

class X
{
public:
    int value;
};

bool operator==(X& left, X& right) 
{
    return left.value == right.value;
};
Run Code Online (Sandbox Code Playgroud)

会员:

class X
{
    int value;
    bool operator==( X& right) 
    {
        return value == right.value;
    };
}
Run Code Online (Sandbox Code Playgroud)

Tim*_*ter 47

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

obj + 2
Run Code Online (Sandbox Code Playgroud)

但对于:

2 + obj
Run Code Online (Sandbox Code Playgroud)

它不会起作用.为此,您需要以下内容:

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) { ... }
Run Code Online (Sandbox Code Playgroud)


Dre*_*ann 9

您最聪明的选择是使其成为朋友功能.

正如JaredPar所提到的,全局实现无法访问受保护的和私有的类成员,但成员函数也存在问题.

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

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

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


X x1, x2;
Y y1, y2;
Run Code Online (Sandbox Code Playgroud)

只有以下某些表达式将使用成员函数进行编译.

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
Run Code Online (Sandbox Code Playgroud)

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

class X
{
    int value;

public:

    friend bool operator==( X& left, X& right ) 
    {
        return left.value == right.value;
    };
};
Run Code Online (Sandbox Code Playgroud)


Dav*_*eas 6

总结Codebender的答案:

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

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;
}
Run Code Online (Sandbox Code Playgroud)

如果运算符是成员函数,则上面的代码将无法编译,而如果运算符是自由函数,它将按预期工作.

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

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;
}
Run Code Online (Sandbox Code Playgroud)


Jar*_*Par 5

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

当您想要禁用某些操作符(如赋值)时,这尤其有用

class Foo { 
  ...
private:
  Foo& operator=(const Foo&); 
};
Run Code Online (Sandbox Code Playgroud)

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