Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Output stream as class member

I have a c++ library that provides an object with complicated logic. During data processing, this object outputs lots of things to std::cout (this is hardcoded now). I would like the processing output not to go to standard output but to a custm widget (some text displaying). I tried to create a std::ostream class member, set it with a parameter (std::cout for console application and some other ostream handled inside GUI application). But the compiler throws me following errors:

[ 14%] Building CXX object src/core/CMakeFiles/PietCore.dir/pvirtualmachine.cpp.o
/usr/include/c++/4.6/ostream: In constructor ‘PVirtualMachine::PVirtualMachine(QString)’:                                                                        
/usr/include/c++/4.6/ostream:363:7: error: ‘std::basic_ostream::basic_ostream() [with _CharT = char, _Traits = std::char_traits]’ is protected
/home/tomasz/Development/C++/piet/src/core/pvirtualmachine.cpp:33:50: error: within this context
In file included from /usr/include/c++/4.6/ios:45:0,
                 from /usr/include/c++/4.6/ostream:40,
                 from /usr/include/c++/4.6/iterator:64,
                 from /usr/include/qt4/QtCore/qlist.h:50,
                 from /usr/include/qt4/QtCore/qvector.h:48,
                 from /usr/include/qt4/QtGui/qpolygon.h:45,
                 from /usr/include/qt4/QtGui/qmatrix.h:45,
                 from /usr/include/qt4/QtGui/qtransform.h:44,
                 from /usr/include/qt4/QtGui/qimage.h:45,
                 from /usr/include/qt4/QtGui/QImage:1,
                 from /home/tomasz/Development/C++/piet/src/core/pcodepointer.h:17,
                 from /home/tomasz/Development/C++/piet/src/core/pblockmanager.h:9,
                 from /home/tomasz/Development/C++/piet/src/core/pvirtualmachine.h:10,
                 from /home/tomasz/Development/C++/piet/src/core/pvirtualmachine.cpp:4:
/usr/include/c++/4.6/bits/ios_base.h: In member function ‘std::basic_ios& std::basic_ios::operator=(const std::basic_ios&)’:
/usr/include/c++/4.6/bits/ios_base.h:791:5: error: ‘std::ios_base& std::ios_base::operator=(const std::ios_base&)’ is private
/usr/include/c++/4.6/bits/basic_ios.h:64:11: error: within this context
In file included from /usr/include/c++/4.6/iterator:64:0,
                 from /usr/include/qt4/QtCore/qlist.h:50,
                 from /usr/include/qt4/QtCore/qvector.h:48,
                 from /usr/include/qt4/QtGui/qpolygon.h:45,
                 from /usr/include/qt4/QtGui/qmatrix.h:45,
                 from /usr/include/qt4/QtGui/qtransform.h:44,
                 from /usr/include/qt4/QtGui/qimage.h:45,
                 from /usr/include/qt4/QtGui/QImage:1,
                 from /home/tomasz/Development/C++/piet/src/core/pcodepointer.h:17,
                 from /home/tomasz/Development/C++/piet/src/core/pblockmanager.h:9,
                 from /home/tomasz/Development/C++/piet/src/core/pvirtualmachine.h:10,
                 from /home/tomasz/Development/C++/piet/src/core/pvirtualmachine.cpp:4:
/usr/include/c++/4.6/ostream: In member function ‘std::basic_ostream& std::basic_ostream::operator=(const std::basic_ostream&)’:
/usr/include/c++/4.6/ostream:57:11: note: synthesized method ‘std::basic_ios& std::basic_ios::operator=(const std::basic_ios&)’ first required here 
/home/tomasz/Development/C++/piet/src/core/pvirtualmachine.cpp: In member function ‘void PVirtualMachine::setOutput(std::ostream)’:
/home/tomasz/Development/C++/piet/src/core/pvirtualmachine.cpp:216:11: note: synthesized method ‘std::basic_ostream& std::basic_ostream::operator=(const std::basic_ostream&)’ first required here

I'd be glad if someone pointed me out what is wrong, because I've got no idea...

My code looks like this:

  • .h file
class PVirtualMachine {
  private:
    std::ostream output;
    [...]
  public:
    void setOutput(std::ostream);
    [...]
};
  • .cpp file
void PVirtualMachine::setOutput(std::ostream os)
{
  output = os;
}
like image 926
ducin Avatar asked Jan 27 '13 01:01

ducin


2 Answers

You've got two options here:

  • Use references, or
  • Use pointers

You can't use normal instances because ostream is non-copyable.

Using references (direct reference to an already-instantiated ostream)

class PVirtualMachine {
  private:
    std::ostream & output;
    [...]
  public:
    PVirtualMachine(std::ostream &);  // Reference must be initialized on construction.
    [...]
};

Advantages:

  • No pointer syntax.
  • Should always refer to a valid instance of std::ostream, as long as the original variable is not deleted.

Disadvantages:

  • The PVirtualMachine class must be constructed with the output reference in the initialization list, otherwise it will not compile.
  • Cannot change the reference once it has been initialized.
  • Cannot work with move-assignment operators (i.e. operator=(PVirtualMachine &&))

Using pointers (optional reference to object)

class PVirtualMachine {
  private:
    std::ostream * output;
    [...]
  public:
    void setOutput(std::ostream *);
    [...]
};

Advantages:

  • Can be instantiated as a null pointer.
  • Can be passed around easily.
  • Can be updated to point to a new std::ostream instance.
  • Can be created internally or externally to the PVirtualMachine instance.
  • Works with move-assignment operator.

Disadvantages:

  • Pointer syntax.
  • Must check for null references when accessing the ostream and/or in the constructor.
like image 144
Karl Nicoll Avatar answered Oct 05 '22 23:10

Karl Nicoll


You can use a reference to a std::ostream instead, this would support any kind of output stream, e.g. stdout, file, etc. This is fine as long as you only want to use one single stream, and the stream doesn't get destroyed:

class PVirtualMachine {
  private:
    std::ostream & output;
    [...]
  public:
    PVirtualMachine(std::ostream & os = std::cout): output(os) { }
    // void setOutput(std::ostream & os) { output = os; } // can't change the reference
    [...]
};

If you want this class to share the stream (therefore keeping it alive for this class's lifetime), use a std::shared_ptr<std::ostream> instead of a reference.

like image 39
Anders Johansson Avatar answered Oct 05 '22 23:10

Anders Johansson