3

我知道我应该从“operator<<”返回“ostream&”,以便能够像这样“链接”操作员

cout<<a<<b<<c;

但是,在下面的代码中,我没有返回“ostream&”,并且仍然可以进行链接。为什么?

#include <iostream>
using namespace std;

class CComplexNumber{
    float m_realPart;
    float m_imagPart;
public:
    CComplexNumber(float r,float i):m_realPart(r),m_imagPart(i){}

    friend ostream& operator<<(ostream& lhs,CComplexNumber rhs){
        lhs<<"["<<rhs.m_realPart<<","<<rhs.m_imagPart<<"]"<<endl;
        //MISSING RETURN STATEMENT!
    }
};

int main() {
    CComplexNumber a(1,2);
    CComplexNumber b(3,4);
    CComplexNumber c(5,6);

    cout<<a<<b<<c;

    return 0;
}

输出

[1,2]
[3,4]
[5,6]
4

3 回答 3

8

从非 void 函数的末尾脱落是未定义的行为。一种可能的未定义行为正在按您预期的方式工作,即返回到位。

g++ 提供了一个方便的警告,以防止这种情况发生在您身上。

于 2013-07-30T17:34:10.553 回答
3

正如其他人指出的那样,您已经调用了未定义的行为:任何事情都可能发生。如果你幸运的话,你会撞车。看来你运气不好。

如果您对它在这种情况下发生的原因感兴趣,您应该查看生成的程序集。我的即兴猜测是,指向的指针lhs留在了返回平台上的值的寄存器中。而且由于 C++ 中的引用通常是用指针实现的,这与将 ref 返回到lhs.

但这是一次彻头彻尾的暗中尝试,最终不是很有趣或很重要。只听编译器的警告,不要那样做。

于 2013-07-30T17:40:36.610 回答
1

这是“纯粹的运气”。函数的返回值在特定的寄存器中。由于您现有的代码已经调用了operator<<,因此它会为您返回正确的内容,因此只要在那之后不涉及其他代码,您就可以从operator<<. 添加一个std::string s = "xyz";"(并s在代码中的某处使用),它可能会中断,因为在函数std::string末尾调用的析构函数“破坏”了operator<<. 所以依赖这个是非常危险的,因为无害的变化会导致它“翻倒”。

于 2013-07-30T17:50:36.763 回答