写入ostream的const引用

时间:2014-11-10 17:48:07

标签: c++ reference const cout

我正在阅读C ++入门书。我遇到了以下代码:

#include <iostream>
#include <string>

using namespace std;

class PrintString {
public:
    PrintString(ostream &o = cout, char c = ' '): os(o), sep(c) {}
    void operator() (const string &s) const { os << s << sep; }
private:
    ostream &os;
    char sep;
};


int main() {
    const PrintString printer;

    printer("ABC");

    return 0;
}

此代码有效,但我不知道为什么。以下是我的想法,如果有人能帮助指出我错在哪里会很棒......

这里,'printer'是一个const PrintString对象,因此它的数据成员是const,所以'printer.os'是对cout的const引用。因此,我们不应该写'printer.os',因为写cout会改变它。

提前致谢!

3 个答案:

答案 0 :(得分:4)

引用不会被修改,只会被修改。这与指针的作用相同。如果您有指向int数据成员(int*)的指针,则在const成员函数中使用它将使其类型为int* const。您无法更改指针本身,但您可以更改它指向的内容。例如:

struct Foo
{
    int a;
    int* p = &a;

    void foo() const
    {
        p = new int; // ERROR! Not allowed to modify const pointer
        *p = 100; // OK, it's a pointer to a non-const int
    }
};

因此,在使用os时,您只需修改其引用的对象,而不是修改引用本身。

答案 1 :(得分:2)

使用指针而不是引用更好地解释了与const的混淆。

说你有:

struct A {int data;};

struct B
{
   B(A* ptr) : aPtr(ptr) {}
   A* aPtr;
};    

int main()
{
   A a1;
   A a2;
   const B b(&a1);
   // This makes b a const object.
   // This makes b.aPtr a const pointer. That means, you cannot change where it points to
   // but you can still change the value of what it points to.
   b.aPtr = &a2; // Not ok.
   b.aPtr->data = 10; // OK.    
}

b.aPtr的常量类似于使用原始指针时的效果。

int main()
{
   A a1;
   A a2;
   A* const aPtr1 = &a1;
   // This makes aPtr1 a const pointer. That means, you cannot change where it points to
   // but you can still change the value of what it points to.
   aPtr1 = &a2; // Not ok.
   aPtr1->data = 10; // OK.

   A const* aPtr2 = &a1;
   // This makes aPtr2 a pointer to a const object. That means, you can change where it points to
   // but you cannot change the value of what it points to.
   aPtr2 = &a2; // ok.
   aPtr2->data = 10; // Not ok.
}

当涉及到参考时,它是相似的,但有一点点扭曲。没有非const引用这样的东西。引用一旦初始化,就无法引用另一个对象。

A a1;
A& ref = a1;  // ref cannot be changed to reference any other object.

在你的情况下,

const PrintString printer;

对成员变量const的{​​{1}}没有影响。它继续引用非PrintString::os const。这允许您使用:

ostream

答案 2 :(得分:1)

尝试将引用成员视为const指针成员变量,以及在声明此类的const对象时const的传播方式如何传播到成员变量。获得const的是指针本身,而不是它指向的内容。引用发生了相同的语义,事实是引用已经是const(就像一个const指针变量),所以它不会为它们改变任何东西。

#include <iostream>

struct S {
    int *p;
    int *const cp;
    int &ref;
};

int main() {
    using namespace std;

    int i = 10;
    const S s{&i, &i, i};

    // s.p = &i; // can't do this, s.p gets const

    *s.p = 20;  // changing the pointee
    cout << i << endl;

    // s.p = &i; // can't do this, s.p was const already, and would get if it weren't

    *s.cp = 30;  // changing the pointee
    cout << i << endl;

    // s.ref ?; // can't make a reference refer to other object

    s.ref = 40;  // changing the pointee
    cout << i << endl;
}