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

发布于 2024-07-27 18:28:32 字数 366 浏览 6 评论 0原文

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

全球:

class X
{
public:
    int value;
};

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

会员:

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

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;
    };
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

柠檬色的秋千 2024-08-03 18:28:32

使用非成员运算符(通常声明为友元)的原因之一是因为左侧是执行操作的一侧。 Obj::operator+ 对于: 很好,

obj + 2

但是对于:

2 + obj

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

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) { ... }

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 + 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) { ... }
无法言说的痛 2024-08-03 18:28:32

您最明智的选择是将其设为好友功能

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

C++ 允许函数参数的隐式转换,但不允许 this 的隐式转换。

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

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


X x1, x2;
Y y1, y2;

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

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

为了两全其美,解决方案是以朋友的身份实现:

class X
{
    int value;

public:

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

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.

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

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

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;
    };
};
最笨的告白 2024-08-03 18:28:32

总结一下 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;
}

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

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

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;
}

To sum up to the answer by 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;
}
挽清梦 2024-08-03 18:28:32

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

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

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

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

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)

暮色兮凉城 2024-08-03 18:28:32

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

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

这是因为第一种形式使用基类中的相等运算符,它可以将其右侧转换为Base。 但派生类相等运算符不能执行相反的操作,因此会出现错误。

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

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.

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).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文