当main()调用一个返回值为某种数据类型(原语或用户定义)的函数时,调用该函数的语句通常是'作业。
前: -
class complex
{
private:
int real;
int imag;
public:
complex();
complex(int r,int i);
complex operator + (complex c);
};
假设,我的重载"的定义+"是这样的 -
complex complex::operator + (complex c)
{
this->real = this->real + c.real;
this->imag = this->imag + c.imag;
return *this;
}
我的主要功能如下 -
int main()
{
complex c1;
complex c2(5,4);
c1+c2;
}
在上面的main()中,考虑语句 c1 + c2 。编译器将其视为 c1.operator +(c2)。当main调用此函数时,它会向main()返回一个值。这个返回值会发生什么变化?
答案 0 :(得分:8)
您的代码会忽略表达式c1+c2
的值,因为您不会将其存储在任何位置。最多,编译器将打印一些警告消息。要压制此类警告消息,您可以写:
(void)(c1+c2); //casting to void suppresses the warning messages!
见:
但是,在您的代码中,operator+
的实现在语义上并不正确。要明白这一点,
int a=10;
int b=5;
那么,您希望a+b
更改a
的值吗? a
应该成为15
吗?没有。
如果你想要,那么你会写a+=b
。但是在您的代码中,c1+c2
的行为与c1+=c2
的语义相同,因为您在this->real
的实现中更新了this->imag
和operator+
的值,这在语义上是不正确的。
所以第一个修复是这样的:
complex complex::operator + (const complex& c) const
{
complex result(c); //make a copy of c
result.real += this->real; //add
result.imag += this->imag; //add
return result;
}
现在,这在语义上是正确的。
尽管如此,仍然有一些事情需要注意。当您编写c1+c2
时,您是否认为操作+
适用于任何一个对象?不。它不适用于它们中的任何一个,但成员函数operator+
在c1
对象上被调用,该对象在函数内变为this
指针。如果操作不适用于c1
(或者c2
),为什么要调用它?
该分析清楚地表明operator+
不应该是该类的成员函数。它应该是非成员函数,而签名则是:
complex operator+(const complex &a, const complex &b);
但是存在一个小问题:在a+b
的计算中,它需要访问类的私有成员(real
和imag
是私有成员)。因此,解决方案是operator+
应该以{{1}}实现,而后者应该作为成员函数添加到类中,因为表达式operator+=
中的操作+=
确实适用于a+=b
,因为它会修改其值。
所以这是我对两个运算符的实现:
a
或者您可以将最后两个语句加入:
class complex
{
//...
public:
//member function
complex& operator+=(const complex & c)
{
real += c.real; //same as: this->real+=c.real; this is implicit
imag += c.imag; //same as: this->imag+=c.real; this is implicit
return *this;
}
};
//non-member function (its non-friend as well)
complex operator+(const complex &a, const complex &b)
{
complex result(a); //make copy of a by invoking the copy-constructor
result += b; //invokes operator+
return result;
}
但还有另一种制作副本的方法。为什么通过引用传递两个参数?按值传递第一个参数将使我们需要的副本。因此,更好的实施方式是:
complex operator+(const complex &a, const complex &b)
{
complex result(a); //make copy of a by invoking the copy-constructor
return result += b; //invokes operator+, and then return updated 'result'
}
希望有所帮助。
答案 1 :(得分:2)
它被分配到一个时间(如果可能的话,不可见)复杂的值。这种值的生命周期直到生成它的表达式结束,那就是;在c1 + c2的末尾。因此,创建一个新的临时对象来存储表达式的结果,并在该行的末尾对其进行破坏。
你不应该在a + b算子中修改'this',在评估a + b后现在a保存表达式的结果。
答案 2 :(得分:2)
丢弃return
值;因为你没有把它存放在任何地方。
一个重要建议:
理想情况下,operator +
的定义应如下所示。
complex complex::operator + (const complex& c)
{ ^^^^^^^^^^^^^^
complex add;
add.real = this->real + c.real;
add.imag = this->imag + c.imag;
return add;
}
在您的原始代码中,制作了2份complex
副本;其中至少有1个可以避免使用上述格式,其中参数通过const引用。
此外,在您的代码中,您不应该更改当前对象; (否则它变得像operator +=()
)。因此,在函数内部创建一个临时函数并按值传递。
答案 3 :(得分:1)
在这种情况下,它会被静默删除(但总和存储在c1
或c2
)中。编译器可能(或可能不)通过完全删除行来优化代码,因为它没有做任何实质性的事情。结果总和将由operator+
构造并返回,(将创建一个临时变量),然后立即销毁。
在其他情况下也会发生这种情况。考虑一下:
c2 += c1;
您可以将这样的几个附加链接在一起:
c4 += c3 += c2 += c1;
这是因为operator+=
也会返回一个值,但会像代码一样被忽略。
顺便说一下,我想你想使用operator+=
。
答案 4 :(得分:0)
它被简单地丢弃了,但是当一个期望返回值的函数没有return语句时,AFAIK C ++会显示错误。
答案 5 :(得分:0)
另一个解决方案是在全局范围内使用operator +
,但作为班级的朋友:
class complex
{
// ...
public:
// ...
friend complex operator +(const complex &c1, const complex &c2)
{
complex c;
c.real = c1.real + c2.real;
c.imag = c1.imag + c2.imag;
return c;
}
// ...
};
使用这种技术,您还可以使用整数作为参数(在lhs)添加:
friend complex operator +(const int n, const complex &c)
{
complex c;
c.real = n + c.real;
c.imag = c.imag;
return c;
}
friend complex operator +(const complex &c, const int n)
{
complex c;
c.real = c.real + n;
c.imag = c.imag;
return c;
}
所以现在你也可以做
complex c1, c2, c3;
c3 = 1 + c2 + 8 + c1 + 2;
并且你的类缺少(虚拟)析构函数,我也会使成员变量受保护而不是私有:)