C++运算符重载 - 重载输出运算符 "<<"

3

我可以帮您进行翻译。以下是需要翻译的内容:

我刚开始学习基本的C++语法,对我遇到的一段代码有些困惑。

对于一个名为MyString的类,定义了一个操作符重载:

ostream& operator<<(ostream& os, const MyString& s)
{
    os << s.data;
    return os;
}

然后在某些驱动程序函数中,有这样一条语句:
cout << s3 << endl;

这行代码是声明了一个名为ran的函数,其中s3是MyString类型的对象。该结果输出s3的值。

我不太理解这个语句如何起作用。经过测试后,似乎调用了一次复制构造函数,然后销毁了3个对象。这条语句到底是如何工作的?看起来运算符接受一个ostream和MyString的引用,但endl并不是这种情况吧?当两个"<<"实例被使用时,为什么只会调用1次复制构造函数呢?也许我问的问题不正确或者我的问题根本没有意义,因为我对这些语句中发生的事情感到非常困惑。如果是这种情况,请有人解释一下正在发生的事情的概述。


你正在学习哪本C++书? - Greg Hewgill
3
这个问题过于宽泛,无法在此作出回答。你需要参考一本好书。 - Nim
C++ Primer 4th Ed.,作者Lippman - KWJ2104
1
你把那叫做基本的C++语法?而且,当你刚开始学习C++时就开始重载运算符了吗 :) ? - ScarletAmaranth
如果您想让我们解释MyString实例有多少个副本,您需要提供更完整的代码示例。没有完整的示例,我们无法诊断此问题。 - André Caron
我认为,这实际上是三个问题:a)什么是按引用调用? b)什么是运算符重载? c)什么是运算符优先级? - 尽管有很多信息。 - moooeeeep
5个回答

7

这是一个很常见的问题,但我会试着澄清你的误解。

当你写下ostream& operator<<(ostream& os, const MyString& s) { ... }时,你定义了一个函数,这个函数接受一个ostream&作为第一个参数,一个const Mystring&作为第二个参数,并返回一个ostream&。这个函数恰巧被命名为operator<<,可以通过简写语法x << y调用operator<<(x, y)

当你执行cout << s3 << endl;时,这与执行operator<<(operator<<(cout, s3), endl);相同。

这段代码中既没有调用MyString的复制构造函数,也没有调用析构函数。你看到的信息来自其他地方。


1

你可以把它分解一下:

cout // this is the ostream your inserting to (stdout)
  << s3 // this calls your defined operator that writes s.data
  << endl; // this calls the operator<< for std::endl

ostream& operator<<(ostream& os, const MyString& s)
{
    // here os is the ostream (stdout) you're using via cout
    // s is s3 that you passed in
    os << s.data; // this calls operator<< for data
    return os; // this returns the reference so the subsequent call to << endl can append to the stream
}

0

不需要调用MyString的复制构造函数来执行此语句,因为MyString被作为引用传递给MyString的自定义运算符<<。

endl未发送到MyString的自定义运算符<<中。


那么 s3 << endl 没有使用重载运算符,但是 cout << s3 是吗?这是因为 s3 << endl 不符合所需的 ostream&/MyString& 参数吗? - KWJ2104
没有 s3<<endl,它是 ((cout << s3) << endl),第一个运算符的结果是 cout。 - Andy Thomas

0

我猜测你的编译器可以为cout生成复制构造函数。流是一个相当复杂的对象,但C++的选择是提供这样的语法糖(如内联构造函数)来抽象一些细节。其他答案已经指出了使用引用进行参数传递时不执行任何复制的关键点。


0

语言规则规定,如果非成员函数(operator<< 是类MyString的非成员函数)在与MyString相同的命名空间中定义,则编译器可以选择该非成员函数来解析该调用(正如其中一位回答者所解释的那样)。我这里没有使用标准术语,如果有人对这个原则有更准确的描述,请告诉我们。


当我从MSVC2003切换到MSVC2005时,我亲身经历了这种行为:我有像ofstream("log") << "here..\n"这样的代码。在切换后,文件中出现了垃圾(指针值),而不是消息。 - CapelliC

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接