2

我有两个关于超载的问题。

1-为什么有时会使重载运算符成为非成员函数?

friend Class operator-(const Class &rhs);

2-有什么区别

Class operator+(const Class &c1, const Class &c2);

Class operator+(const Class &rhs);

如果我想添加两个对象C3 = C1 + C2

任何帮助表示赞赏...

4

3 回答 3

4

如果将二元运算符作为成员函数重载,它最终会不对称:左操作数必须是运算符重载的确切类型,但右操作数可以是任何可以转换为正确类型的东西。

如果使用非成员函数重载运算符,则可以转换两个操作数以获得正确的类型。

你的第二点看起来像是同一点的一个具体例子,根本没有任何分开的东西。这是我正在谈论的一个具体示例:

class Integer {
    int val;
public:
    Integer(int i) : val(i) {}
    operator int() { return val; }

    // Integer operator+(Integer const &other) const { return Integer(val + other.val); }

    friend Integer operator+(Integer const &a, Integer const &b) { 
        return Integer(a.val + b.val);
    }
};


int main() { 
    Integer x(1);

    Integer y = x + 2; // works with either operator overload because x is already an Integer

    Integer z = 2 + x; // works with global overload, but not member overload because 2 isn't an Integer, but can be converted to an Integer.
    return 0;
}

另请注意,即使friend函数的定义在 的类定义中Integer,它被声明为友元这一事实意味着它不是成员函数——将其声明为friend使其成为全局函数,而不是成员。

底线:这种重载通常应该作为自由函数而不是成员函数来完成。为用户提供正确(极大地)工作的运算符比“更面向对象”之类的理论考虑更重要。必要时,比如当操作符的实现需要是虚拟的时,你可以做一个两步的版本,你提供一个(可能是虚拟的)成员函数来做真正的工作,但重载本身是一个自由函数,在其左操作数上调用该成员函数。一个相当常见的例子是operator<<层次结构的重载:

class base { 
    int x;
public:
    std::ostream &write(std::ostream &os) const { 
        return os << x;
    }
};

class derived : public base { 
    int y;
public:
    std::ostream &write(std::ostream &os) const { 
        return (base::write(os) << y);
    }
};

std::ostream &operator<<(std::ostream &os, base const &b) {
    return b.write(os);
}

这支持多态实现(以及访问基类的受保护成员,如有必要),而不会放弃操作符的正常特性来获取它。

将二元运算符重载为自由函数的主要例外是赋值运算符(operator=operator+=operator-=operator*=)。转换会产生一个临时对象,无论如何您都不能分配给它,因此对于这种特殊情况,重载应该(实际上必须是)一个成员函数。

于 2012-07-27T04:07:55.513 回答
2

1-为什么有时会使重载运算符成为非成员函数?

这是选择的问题。您可以将其operator +/-设为类成员或使其成为免费friend函数。
如果它是一个自由函数,您提供的语法operator -是错误的friend,它应该采用 2 个参数(类似于operator +您的示例)。

2-有什么区别

如前所述,它只是语法不同。第一个应该是自由friend函数,第二个是class成员。

最重要的是,我相信将运算符保留为class成员方法比自由函数要好,因为:

  1. 如果适用,成员方法可以访问protected基类的成员,但friend函数不能
  2. 成员方法是更面向对象的方法,因为您关联了与类相关的方法
于 2012-07-27T03:55:15.817 回答
0

让重载的运算符成为朋友是一个更好的选择,因为以这个例子为例

class Comples
{
   public:
      Complex(float real, float imaginary);
      friend operator+ (const Complex &rhs);
   ...
};

通过让操作员成为朋友,您可以执行以下操作

Complex result1 = 5.0 + Comples(3.0, 2.0);

Complex result1 = Comples(3.0, 2.0) + 5.0;

遵守加法社区属性的规则。如果重载的运算符是成员函数,则无法实现这一点。这是由于编译器能够Complex在这种情况下根据需要隐式创建对象。因此,加法运算符作为朋友时的行为符合数学中的正常加法概念。

于 2012-07-27T04:08:22.317 回答