成员与非成员函数,返回副本还是引用?

时间:2016-11-22 10:32:32

标签: c++

是否有任何"规则"什么样的返回类型成员与非成员函数应该有什么?

我正在构建一个复杂类,我认为成员函数将是返回类型引用,非成员函数将是副本。这是对的吗?

Complex.h供参考:

#include <iostream>
#include <string>

#ifndef COMPLEX_H
#define COMPLEX_H


class Complex {

  public:
    double real;
    double imaginary;


    Complex();
    Complex(const double real);
    Complex(const double real, const double imaginary);
    Complex(const Complex &rhs);

    Complex& operator *= (const Complex&);
    Complex& operator += (const Complex&);
    Complex& operator /= (const Complex&);
    Complex& operator -= (const Complex&);
    Complex& operator = (const Complex&);

};

class Complex;

double abs(const Complex& c);

Complex operator * (const Complex& c1, const Complex& c2);
Complex operator / (const Complex& c1, const Complex& c2);
Complex operator + (const Complex& c1, const Complex& c2);
Complex operator - (const Complex& c1, const Complex& c2);

bool operator == (const Complex& c1, const Complex& c2);
bool operator != (const Complex& c1, const Complex& c2);

std::istream& operator >> (std::istream& in, Complex& c);
std::ostream& operator << (std::ostream& out, const Complex& c);

Complex operator ""_i(long double arg);
Complex operator ""_i(unsigned long long arg);

#endif

3 个答案:

答案 0 :(得分:2)

这不是关于成员与非成员的关系。您在成员函数中返回了引用,因为它们实际上修改了this值。

请考虑以下代码:

Complex c1, c2, c3;
// ...
(c3 *= c2) += c1;

将对c3 *= c2进行评估,然后以operator+=作为参数调用结果c1。如果您返回副本而不是c3 *= c2的引用,则下一个应用的operator+=将修改此返回的副本而不是c3,这不是人们所期望的。

请注意,您可以将其他运算符声明为成员函数,只是为了显示引用vs副本与成员与非成员无关:

class Complex {

    // ...

    Complex& operator *= (const Complex&);
    Complex& operator += (const Complex&);
    Complex& operator /= (const Complex&);
    Complex& operator -= (const Complex&);
    Complex& operator = (const Complex&);

    Complex operator * (const Complex& c2);
    Complex operator / (const Complex& c2);
    Complex operator + (const Complex& c2);
    Complex operator - (const Complex& c2);

};

答案 1 :(得分:2)

当您致电运营商时,您必须查看您对结果的期望。

例如,如果你使用运算符*,你可能会有

//Some Complex instances c1 and c2 already created
Complex c3 = c1 * c2;

您不希望修改c1或c2。所以这里的副本很好。

但是如果使用运算符* =,则期望结果修改调用运算符的Complex实例。所以在这里,引用更好,因为你将避免复制构造函数和析构函数。

所以你提供的例子还可以。

答案 2 :(得分:2)

正如我上面所述,重要的问题不是这是成员还是非成员,而是返回的值是否是新实例。

任何更改对象本身的操作(如++,+ =, - =,...)都应返回对同一对象的引用。另一方面,任何导致另一个对象(如二进制+, - 等等)的操作都必须创建一个新对象,因为永远不应该更改原始操作数。

此外,您可以将一些二元运算符作为成员(例如,complex + int),而其他运算符必须在类外定义(例如,int + complex)。当然,您希望这两个操作的行为相同。