重载运算符<<对于ostream语法

时间:2012-02-27 19:42:53

标签: c++ operator-overloading ostream

上个学期,我一直在上课。 这是打印出链表对象的给定打印功能。 我不明白为什么重载运算符需要两个参数,一个是一个 os对象。当我们在main.cpp上打印出实际的链表对象时,我们没有 需要传递一个os对象。另外,为什么它会返回os?为什么我们不能只使用cout 而不是“os<<” ?

谢谢!

template <class T>
void List<T>::print(ostream & os) const
{
    os << "<";
    ListNode * curr = head;
    while (curr != NULL) {
        os << " " << curr->data;
        curr = curr->next;
    }
    os << " >";
}



// overloaded operator<<
template <class T>
ostream & operator<<(ostream & os, const List<T> & list)
{
    list.print(os);
    return os;
}

4 个答案:

答案 0 :(得分:6)

顺便问一下这个问题及其基本程度,我将尝试给出一个非常简单的(尽管是非正式的,不那么迂腐)的答案。

  

我不明白为什么重载运算符需要两个参数   一个是os对象

运营商LT;&LT;是一个二元运算符。它有左手侧和右手侧。当你写:

cout << 123;

您正在使用两个操作数(参数)调用此运算符:左侧为“cout”,右侧为整数“123”。

  

当我们在main.cpp上打印出实际的链表对象时,我们   不需要传递os对象。

您的打印功能是类的成员函数或运算符。这将隐含地推断出粗略地说第一个参数不需要显式传递,因为你已经有了'this'指针来处理你的列表对象。非成员运算符的情况并非如此,因为您没有隐式推导出的'this'对象已经用于左侧操作数。

当你编写这样的代码时:

my_list.print(cout);

您可以将其视为实际传递两个参数,'my_list'和'cout'。即使你没有明确地写它,你也可以通过'this'及其成员访问'my_list'。如果您将print函数编写为非成员,则情况并非如此:

template <class T>
void print(const List<T>& my_list, ostream& os);

您的运营商也不是会员职能。

  

另外,为什么要返回os?

返回对ostream的引用是允许我们编写这样的语句的原因:

cout << "hello " << "world";

首先我们调用operator&lt;&lt;(cout,“hello”)然后给我们另一个ostream引用,然后允许我们继续调用operator&lt;&lt;(cout,“world”)。例如,如果它返回void,它将不允许我们在一个语句中两次调用该运算符,因为我们试图输出带有void作为左侧操作数的“world”。

  

为什么我们不能只使用cout而不是“os&lt;&lt;” ?

cout基本上实现了ostream接口。 ofstream,ostringstream和其他类型的输出流也是如此。通过根据所需的基本接口编写它而不是某些特定的ostream衍生物,您可以允许您编写的代码使用stdio流,文件流,流和其他流。基本上它使您的代码非常通用和可重用,这是您在实际应该努力做的事情。在解决多态性的概念时,您将更多地了解这个主题。

答案 1 :(得分:2)

因为它是全局非成员函数。使用成员函数版本,第一个参数隐式地是调用对象this。这意味着你的班级必须始终在左侧。使用非成员函数,它是一个显式参数;这样,您可以指定所需的任何类型,并为无法修改源的类重载运算符(只要至少一个参数是用户定义的类型)。

您使用os的原因是它适用于文件流和所有内容(任何继承自ostream的内容),而不仅仅是cout

返回os,以便您可以对返回值执行更多operator<<次调用。这使得操作员链接(例如w << x << y << z)与operator<<(operator<<(operator<<(w, x), y), z)相同。如果您返回void或其他内容,则必须停在w << x,因为您无法对void的返回值执行任何操作。

答案 2 :(得分:0)

  

我不明白为什么重载运算符需要两个参数,一个是os对象。当我们在main.cpp上打印出实际的链表对象时,我们不需要传递一个os对象。

是的,你做了:当你说cout << x时,你将coutx传递给operator<<

  

另外,为什么要返回os?

使cout << x << y成为可能。这被解析为(cout << x) << y,即它将y插入cout << x的返回值。

  

为什么我们不能只使用cout而不是“os&lt;&lt;” ?

因为有时您想输出到标准输出以外的其他流。

答案 3 :(得分:0)

  

当我们在main.cpp上打印出实际的链表对象时,我们   不需要传递os对象。

是的,你做了...... cout << obj;,其中cout是os输出流。

  
    

另外,为什么它会返回os?为什么我们不能只使用cout而不是“os&lt;&lt;” ?

  

这允许链接:cout << obj << " " << obj2;

  
    

为什么我们不能只使用cout而不是“os&lt;&lt;” ?

  

这会硬连接输出流,因此您无法写入文件或任何其他输出。