云中孤鹤

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

C++中,我们可以重载输入输出流操作符<<与>>来自定义其输入输出功能。

class Foo
{
public:
    Foo() :high(0), wide(0){}
    Foo(int a, int b) :high(a), wide(b){}

    Foo & operator++();//前置
    const Foo operator++(int);//后置调用前置

    friend const ostream& operator<< (const ostream&,const Foo&);
    //这样写 流对象之前加const常量限制符,会报错
private:
    int high;
    int wide;
};

const ostream& operator<< (const ostream& os, const Foo& foo)
{
    os << foo.high << " " << foo.wide;
    return os;
}

上面的写法 在流对象之前使用 const ,编译器会报错,报错提示如下:

image

错误提示原因是 输入流对象 没有匹配的 常量类型 输出。说白了就是 输出流操作 不能在输出 一个数据流而其本身没有任何变化。(如果理解不了这句话,可以先跳过,往后继续看,相信看完之后再来看这句话,就能理解了)

下面来试试去掉const常量修饰符之后的结果:

class Foo
{
public:
    Foo() :high(0), wide(0){}
    Foo(int a, int b) :high(a), wide(b){}

    Foo & operator++();//前置
    const Foo operator++(int);//后置调用前置

    friend ostream& operator<< (ostream&,const Foo&);
    //这是去掉const常量修饰符,正确的做法

private:
    int high;
    int wide;
};

ostream& operator<< (ostream& os, const Foo& foo)
{
    os << foo.high << " " << foo.wide;
    return os;
}

编译通过,没有报错。

为什么加上const 修饰符之后,就是错误的呢?const 是用来修饰不会改变的 对象或变量状态的常量修饰符。而此处不能在重载的流对象之前加 const 说明 Foo类的友元函数 输出流对象 之后改变了流对象本身的状态。

C++ primer 对此的描述是“读写IO对象会改变其状态,返回的引用不能是const“。

那么一个流对象,使用之后,其状态为什么被改变了呢?

我们先来想一下我们处理一个文本文件的场景:先打开一个文本文件,获得其句柄,通过该句柄可以对其读写操作(注意此处的读写操作,很像我们的流操作。其实C++的文件操作,标准化就是通过重载<<与>>进行流读写的)。文件读写通过两个文件指针,一个读指针,一个写指针,每次进行读或写操作,读写指针就会自动往后移动。注意这里,读写指针自动移动。这里就已经改变了文件的流对象 的状态。

同理,我们的屏幕输出流对象和键盘输入流对象,也有这么类似的一对自动移动的读写指针,每次进行流操作时,例如在屏幕打印一个字符,屏幕输出流对象的位置指针就会向后移动一个单位。这里就改变了流对象的状态。

下面引用一位网友对此形象的描述:河里的水流虽然看起来没有变化,但是有水流过,肯定有东西发生了变化(河床发生了侵蚀,沙子发生了沉积)。

posted on 2017-11-13 22:59  云中孤鹤  阅读(6010)  评论(0编辑  收藏  举报