是否有任何"规则"什么样的返回类型成员与非成员函数应该有什么?
我正在构建一个复杂类,我认为成员函数将是返回类型引用,非成员函数将是副本。这是对的吗?
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
答案 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)。当然,您希望这两个操作的行为相同。