在c+中使用友元函数进行I/O运算符重载+; 我自己学习C++。我在学习运算符重载,我能够理解加减运算符重载。但是I/O操作符的重载有点令人困惑。 我已经为复数创建了一个类,现在我正在重载运算符

在c+中使用友元函数进行I/O运算符重载+; 我自己学习C++。我在学习运算符重载,我能够理解加减运算符重载。但是I/O操作符的重载有点令人困惑。 我已经为复数创建了一个类,现在我正在重载运算符,c++,operator-overloading,iostream,friend-function,C++,Operator Overloading,Iostream,Friend Function,Complex.h中的函数原型 friend ostream& operator<<(ostream&, const Complex&); friend-ostream&operatorForfriend-ostream&operator 有人能解释一下(在基本层面上)为什么我们必须在这里使用友元函数声明吗 如果您声明了一个类另一个类的朋友,那么您是说朋友类可以访问您的类的私有和受保护的属性和函数。 对于非友元成员函数运算符,声明ostream&opera

Complex.h中的函数原型

friend ostream& operator<<(ostream&, const Complex&);

friend-ostream&operatorFor
friend-ostream&operator
  • 有人能解释一下(在基本层面上)为什么我们必须在这里使用友元函数声明吗

    如果您声明了一个类
    另一个类的朋友,那么您是说朋友类可以访问您的类的私有和受保护的属性和函数。

    对于非友元成员函数运算符,声明
    ostream&operator
    friend ostream&operator,只有一个参数,即运算符的右侧。对于除法运算符的示例,您可以这样做:

    Complex a = ...;
    Complex b = ...;
    
    Complex c = a / b;
    
    编译器实际上会将最后一个视为

    Complex c = a.operator/(b);
    
    这意味着,例如,对于输出运算符,如果它是一个普通成员函数,则“输出”到类的实例。换言之,它的用法如下

    Complex a = ...;
    Complex b = ...;
    a << b;  // Really a.operator<<(b);
    
    complexA=。。。;
    复合物b=。。。;
    A.
    有人能解释一下为什么我们要在这里使用friend函数吗

    类的
    友元
    可以从指定为
    友元的类访问
    私有
    受保护的
    变量/函数。如果I/O操作员需要访问任何私有功能,则有必要使其成为类
    复杂
    朋友
    。如果不是,可以简单地在类之外定义函数,而不声明函数本身

    为什么我们必须通过引用传递运算符

    我不知道你的意思。运算符是我们正在定义的函数,而不是在任何地方传递的参数。你指的是它需要的参数吗?嗯,
    std::ostream
    被作为引用类型,因为按值获取它会导致复制,这是流类不允许的。尝试一下,你会得到一个编译器错误。下面我将谈谈为什么将
    Complex
    作为参考类型

    此函数在不使用
    const
    的情况下运行良好,但为什么我们在这里使用
    const
    ?作为常量对象传递
    Complex
    有什么好处

    首先,为什么不使用
    const
    const
    type修饰符对编译器来说是一个明确的语句,我们不会以任何方式更改对象。它还向代码的维护人员说明了这一点。此外,写出一个对象通常需要这个值,这意味着不需要修改对象

    使用对
    const
    的引用还可以将右值或临时值传递给函数,这在引用非
    const
    时是不可能的,因为它只接受左值。例如:

    struct S{};
    无效f(S&);
    空h(S常数&);
    int main()
    {
    S S;
    f(s);//好的
    f(S());//错误!
    h(s);//好的
    h(S());//好的
    }
    
    您不必让流媒体运营商成为朋友。它确实必须在外部声明,因为复杂对象位于操作符的右侧

    但是,如果您的复杂类能够访问所需的成员(可能通过getter),那么您可以让流式处理操作符使用它们。说:

    std::ostream& operator<<( std::ostream& os, Complex const& cpx )
    {
       return os << cpx.getReal() << ',' << cpx.getImaginary();
    }
    

    您显示了两个不同的函数,
    operator+1问题在我看来很清楚。@重复数据消除程序我在这里找不到任何答案,直接参考OP问题中的这3点。如果是这样的话,它就隐藏在那里,只需通过以下附加链接即可访问。@πάνταῥεῖ: 对,它没有解释这些观点的原因。撤回。尽管如此,op还是应该读到这一点:你怎么知道的?您是否可以访问<代码>复合体< /Cord>类定义?不,但这是一个常见的例子,当您开始阅读C++时。成员数据通常是私有的,并且是可操作的。标准示例还包括公共访问器,因此不需要额外的后门。@重复数据消除问题意味着要知道为什么会这样。所以我想给出可能的原因。@LearningC:我们只是反对你说访问私人部分是绝对必要的。更改后,left1没有什么可反对的:
    ostream
    绝对没有被宣布为朋友。2:哪一个对象?我修正了2,在1中操作符被声明为朋友,同样的原理范围更小,我认为这是显而易见的。或者我看到了错误的@Deduplicator吗?在操作符体中,可以访问复杂类的所有私有和受保护的属性和函数。你能解释一下为什么流是不可复制的吗?@user3834119,当然,请看这篇文章:(我将其添加为编辑)你能解释一下为什么流类不允许复制吗?@user3834119因为对于复制流的正确语义没有共识。流具有指向表示其外部设备的流缓冲区的指针。复制流是否也应该复制该指针?那么谁将负责处理缓冲区的破坏?从C++11开始,可以复制流缓冲区,但不能复制实际的流本身。流可以移动,但是大多数编译器还不支持这个新功能。
    Complex a = ...;
    Complex b = ...;
    a << b;  // Really a.operator<<(b);
    
    std::ostream& operator<<( std::ostream& os, Complex const& cpx )
    {
       return os << cpx.getReal() << ',' << cpx.getImaginary();
    }
    
    Complex operator/ ( Complex const& lhs, Complex const& rhs )
    {
        Complex res( lhs );
        res /= rhs; // or just put return in front of this line
        return res; 
    }