Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ extern: pointer vs. reference

Tags:

c++

extern

I have three classes: ConsoleInputStream, ConsoleOutputStream, ConsoleErrorStream. All of them are derived from Stream.

Each stream has virtual functions read and write; as you guess, when user tries to use ConsoleInputStream's write member function, it throws an error. Same happens when user tries to use ConsoleOutputStream's write function.

Now it's time to show the code.

// STREAM.HPP
namespace streamlib {
extern ConsoleInputStream stdin_default;
extern ConsoleOutputStream stdout_default;
extern ConsoleErrorStream stderr_default;
extern Stream& stdin;
extern Stream& stdout;
extern Stream& stderr;
} // namespace streamlib


// STREAM.CPP
namespace streamlib {
ConsoleInputStream stdin_default;
ConsoleOutputStream stdout_default;
ConsoleErrorStream stderr_default;
Stream& stdin = stdin_default;
Stream& stdout = stdout_default;
Stream& stderr = stderr_default;
} // namespace streamlib


// MAIN.CPP
int main()
{
  streamlib::stdout = streamlib::stdin;
  streamlib::stdout.write(); // Still working, but should have thrown error!
}

However, everything works perfectly well when I define stdin, stdout and stderr as pointers instead of references, i.e. error is thrown as expected. But I don't want to allocate/free memory and use -> operator where I could (could I?) use plain dot operator.

The real situation is of course even more intricated: I also have some other types derived from Stream and just want to be able to quickly overload stdin, stdout, stderr streams with different kind of streams. Is it possible to do it with references?

Thanks in advance!

like image 869
ghostmansd Avatar asked Nov 19 '13 12:11

ghostmansd


1 Answers

You cannot do with references what you do with pointers, because references cannot be re-assigned. When you do this to references

streamlib::stdout = streamlib::stdin

it corresponds to an assignment of dereferenced pointers, not plain pointers. In other words, if stdout and stdin were pointers, the equivalent code would have been

(*streamlib::stdout) = (*streamlib::stdin)

This calls the assignment operator of Stream, passing stdin to be assigned to stdout.

One way around this is to define an assignable "pointer stream" that encapsulates a pointer to a "real" stream, and overrides it on assignment by a pointer to whatever stream being assigned to it. This would let you keep the object syntax, letting you use the dot . operator instead of the pointer dereference operator ->.

like image 139
Sergey Kalinichenko Avatar answered Oct 14 '22 17:10

Sergey Kalinichenko