关于重载运算符<<的问题

Question about the overloaded operator <<

本文关键字:lt 问题 运算符 于重载 重载      更新时间:2023-10-16

尝试研究C++函数模板。作为其中的一部分,我有下面的代码。它运行良好,但我有以下问题:-

1] 为什么运算符<lt;重载函数需要成为朋友吗?如果我删除关键字friend,它会给出编译错误:operator<lt;参数太多。

2] 为什么运算符<lt;重载函数是否需要返回对ostream对象的引用,该对象也是它的输入参数?

3] 我对此表示怀疑,但以上两个问题是否与函数模板用于具有重载函数的用户定义类有关?

template <class T>
T Average(T *atArray, int nNumValues)
{
    T tSum = 0;
    for (int nCount=0; nCount < nNumValues; nCount++)
        tSum += atArray[nCount];
    tSum /= nNumValues;
    return tSum;
}
class Cents
{
private:
    int m_nCents;
public:
    Cents(int nCents)
        : m_nCents(nCents)
    {
    }
    //Why is friend needed below
    //Why does it need to return ostream&, why can't it have void return type, as all it is doing is printing the class private member.
    friend ostream& operator<< (ostream &out, const Cents &cCents)
    {
        out << cCents.m_nCents << " cents ";
        return out;
    }
    /* 
    void operator <<( const Cents &cCents) //did not work - compilation errors
    {
        cout << cCents.m_nCents << " cents ";
    }
    */
    void operator+=(Cents cCents)
    {
        m_nCents += cCents.m_nCents;
    }
    void operator/=(int nValue)
    {
        m_nCents /= nValue;
    }
};
int main()
{
    int anArray[] = { 5, 3, 2, 1, 4 };
    cout << Average(anArray, 5) << endl;
    double dnArray[] = { 3.12, 3.45, 9.23, 6.34 };
    cout << Average(dnArray, 4) << endl;
    Cents cArray[] = { Cents(5), Cents(10), Cents(15), Cents(14) };
    cout << Average(cArray, 4) << endl;
    cin.get();
    return 0;
}

为什么运算符<lt;重载函数需要成为朋友吗?如果我删除关键字friend,它会给出编译错误:operator<lt;参数太多。

<<会更改流的状态,因此理想情况下,它应该实现为其左操作数类型的成员。然而,它的左操作数是来自标准库的流,虽然标准库定义的大多数流输出和输入运算符确实被定义为流类的成员,但当您为自己的类型实现输出和输入操作时,您无法更改标准库的数据流类型
这就是为什么您需要为自己的类型实现这些(<<>>(运算符作为非成员函数的原因。由于您需要在运算符定义中访问类对象的私有/受保护成员变量,因此需要将这些重载运算符声明为类的友元。

为什么运算符<lt;重载函数是否需要返回对ostream对象的引用,该对象也是它的输入参数?

通过返回对标准流对象的引用,可以使用对象链接

你可以打这样的电话:

out<<obj1<<obj2;

模板用于具有重载函数的用户定义类?

模板可以帮助您实现通用函数和类,这些函数和类可以针对不同的数据类型,编译器负责为这些特定的数据类型生成代码。因此,以上两点并不相关。


强烈建议阅读以下常见问题条目:
操作员过载

[1]它需要成为友元,因为它试图访问私有成员变量m_nCents,该变量只能由Cents的成员函数或Cents的友元访问。

[2] 这是重载"流媒体运营商"的标准函数签名。这使得连接<< s:成为可能

out << a << b;

相当于

(out << a) << b;

编辑:您似乎希望operator<<成为该类的成员。这是不可能的,因为它的第一个操作数是ostream,而不是Centsfriend实际上将其声明为非成员朋友函数。如果去掉friend关键字,则将其声明为成员函数(因为它在类定义中(,但在这种情况下,它有太多的参数(签名中的两个,以及作为第一个参数的隐式Cents,调用它的一个,如果您喜欢的话,还有this指针(。

operator<<声明为流式传输的非成员函数是标准的方法,无论是否为friend(取决于您是否需要friend,或者以某种方式公开m_nCents(。

它必须返回一个ostream并将其中一个作为参数,这样才能将多个调用链接在一起。

例如:

Cents a,b,c;
cout << a << b << c;

它必须是一个朋友,因为它不是一个成员函数,不管你在class代码块中定义了什么。

让我进一步阐述一下这个概念。上述示例等效于以下内容:

op(op(op(cout,a),b),c);

其中"op"是重载运算符的实际函数名的简写。请注意,它不是在Cents的实例上调用的,事实上也不会有thisptr,因为它就像一个独立的函数一样存在于类之外。