skatrak
skatrak

Reputation: 43

C++ stream reference as class member

I have a class which is sort of like this:

#include <iostream>

class A {
public:
    A (std::istream& is): _is(is) {}

    void setInputSource (std::istream& is) {
        _is = is;
    }

    A& operator>> (int& x) {
        _is >> x;
        return *this;
    }

private:
    std::istream& _is;
};

And I want the _is member to act just as a reference. I mean, it has to "point" to an external std::istream and I don't want the setInputSource() method to copy the stream that is passed as argument. The problem is that the program won't compile because that method that I mentioned is trying to access the operator= of the class std::basic_istream<char>.

My goal is to get the class behave as expected in a program like this:

int main() {
    int a, b;

    std::ifstream ifs("myfile.txt");
    A myA(std::cin);

    myA >> a;
    myA.setInputSource(ifs);
    myA >> b;

    return 0;
}

I thought to use pointers instead, but I prefer to use references as I like the fact that they warrantee you that they won't have invalid values and it seems to me that it's a more elegant approach.

Upvotes: 4

Views: 771

Answers (3)

David G
David G

Reputation: 96810

Sounds like you just want to change the buffer:

class A
{
public:
    A (std::istream& is)
        : m_is(is.rdbuf())
    { }

    void setInputSource(std::istream& is) {
        m_is.rdbuf(is.rdbuf());
    }

    // ...

private:
    std::istream m_is;
};

Upvotes: 1

QuestionC
QuestionC

Reputation: 10064

You can't do this. The only way to define a reference is in the constructor.

It's actually pretty handy because that guarantees that the object will fall out of scope before the reference on which it depends.

For example, with your design, it would be possible to put myA in an invalid state.

int main() {
    int a, b;

    A myA(std::cin);
    myA >> a;

    {
       std::ifstream ifs("myfile.txt");
       myA.setInputSource(ifs);
    }

    myA >> b;

    return 0;
}

You can still shoot yourself in the foot with pointers of course.

Upvotes: 1

Joseph Mansfield
Joseph Mansfield

Reputation: 110658

You can't bind a reference to a different object after it has already been bound. That's one of the fundamental differences between using pointers and using references. Given this, it would be more appropriate for you to use a pointer.

I prefer to use references as I like the fact that they warrantee you that they won't have invalid values

This isn't true. If the object a reference is bound to is destroyed, then it references an invalid object, just as with pointers.

Upvotes: 4

Related Questions