a) When passing by value, the parameter receives a copy. But istream/ostream are not copyable, so it cannot be passed by value. So it is passed by reference.
b) the istream / ostream is modified when reading/writing, again this means it must be passed by reference.
Return type of reference to istream/ostream:
This allows the >> and << operators to be used in the familiar ways we are used to for other types, such as chaining several different items in the same statement, such as
cout << "values are " << a << b << c << endl;
If the reference was not returned, then only a single item could be handled at a time. cout << a;
It also allows testing the outcome in the usual ways, such as
1 2 3
while (infile >> a >> b >> c)
{
// do something with values read from file
Here, the while or if tests the status of the stream after the input operation, and depends on the returned reference.