作为类成员的输出流
Output stream as class member
我有一个 c++ 库,它提供了一个具有复杂逻辑的对象。在数据处理过程中,这个对象会向 std::cout 输出很多东西(现在是硬编码的)。我希望处理输出不是转到标准输出,而是转到 custm 小部件(一些文本显示)。我尝试创建一个std::ostream
类成员,使用参数设置它(控制台应用程序的 std::cout 和 GUI 应用程序内部处理的其他一些 ostream)。但是编译器会给我抛出以下错误:
[ 14%]Building CXX object src/core/CMakeFiles/PietCore.dir/pvirtualmachine.cpp.o/usr/include/c++/4.6/ostream: 在构造函数'PVirtualMachine::P VirtualMachine(QString)'中: /usr/include/c++/4.6/ostream:363:7:错误:"std::basic_ostream::basic_ostream() [_CharT = char,_Traits = std::char_traits]"受保护/home/tomasz/Development/C++/piet/src/core/pvirtualmachine.cpp:33:50:错误:在此上下文中在/usr/include/c++/4.6/ios:45:0 包含的文件中, 来自/usr/include/c++/4.6/ostream:40, 来自/usr/include/c++/4.6/iterator:64, 来自/usr/include/qt4/QtCore/qlist.h:50, 来自/usr/include/qt4/QtCore/qvector.h:48, 来自/usr/include/qt4/QtGui/qpolygon.h:45, 来自/usr/include/qt4/QtGui/qmatrix.h:45, 来自/usr/include/qt4/QtGui/qtransform.h:44, 来自/usr/include/qt4/QtGui/qimage.h:45, 来自/usr/include/qt4/QtGui/QImage:1, 来自/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, 来自/home/tomasz/Development/C++/piet/src/core/pvirtualmachine.cpp:4:/usr/include/c++/4.6/bits/ios_base.h: 在成员函数'std::basic_ios& std::basic_ios::operator=(const std::basic_ios&)'中:/usr/include/c++/4.6/bits/ios_base.h:791:5:错误:"std::ios_base& std::ios_base::operator=(const std::ios_base&)' 是私有的/usr/include/c++/4.6/bits/basic_ios.h:64:11:错误:在此上下文中在/usr/include/c++/4.6/iterator:64:0 包含的文件中, 来自/usr/include/qt4/QtCore/qlist.h:50, 来自/usr/include/qt4/QtCore/qvector.h:48, 来自/usr/include/qt4/QtGui/qpolygon.h:45, 来自/usr/include/qt4/QtGui/qmatrix.h:45, 来自/usr/include/qt4/QtGui/qtransform.h:44, 来自/usr/include/qt4/QtGui/qimage.h:45, 来自/usr/include/qt4/QtGui/QImage:1, 来自/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, 来自/home/tomasz/Development/C++/piet/src/core/pvirtualmachine.cpp:4:/usr/include/c++/4.6/ostream: 在成员函数 'std::basic_ostream& std::basic_ostream::operator=(const std::basic_ostream&)':/usr/include/c++/4.6/ostream:57:11:注意:这里首先需要合成方法'std::basic_ios& std::basic_ios::operator=(const std::basic_ios&)'/home/tomasz/Development/C++/piet/src/core/pvirtualmachine.cpp: 在成员函数'void PVirtualMachine::setOutput(std::ostream)'中:/home/tomasz/Development/C++/piet/src/core/pvirtualmachine.cpp:216:11:注意:这里首先需要合成方法'std::basic_ostream& std::basic_ostream::operator=(const std::basic_ostream&)'
如果有人指出我出了什么问题,我会很高兴,因为我不知道......
我的代码如下所示:
- .h 文件
类光伏机器 { 私人: 标准::流输出; [...] 公共: void setOutput(std::ostream); [...]};
- .cpp文件
void PVirtualMachine::setOutput(std::ostream os){ 输出 = 操作系统;}
这里有两个选项:
- 使用引用,或
- 使用指针
您不能使用普通实例,因为ostream
是不可复制的。
使用引用(直接引用已实例化的ostream
)
class PVirtualMachine {
private:
std::ostream & output;
[...]
public:
PVirtualMachine(std::ostream &); // Reference must be initialized on construction.
[...]
};
优势:
- 无指针语法。
- 应该始终引用
std::ostream
的有效实例,只要原始变量不被删除。
弊:
PVirtualMachine
类必须使用初始化列表中的输出引用构造,否则将无法编译。
初始化引用- 后无法更改引用。
- 不能使用移动赋值运算符(即
operator=(PVirtualMachine &&)
)
使用指针(对对象的可选引用)
class PVirtualMachine {
private:
std::ostream * output;
[...]
public:
void setOutput(std::ostream *);
[...]
};
优势:
- 可以实例化为空指针。
- 可以轻松传递。
- 可以更新为指向新的
std::ostream
实例。 - 可以在 PVirtualMachine 实例的内部或外部创建。
- 与移动赋值运算符配合使用。
弊:
- 指针语法。
- 在访问 ostream 和/或在构造函数中时必须检查空引用。
您可以使用对std::ostream
的引用,这将支持任何类型的输出流,例如标准输出、文件等。只要您只想使用一个流,并且该流不会被销毁,这就可以了:
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
[...]
};
如果希望此类共享流(因此在此类的生存期内保持活动状态),请使用 std::shared_ptr<std::ostream>
而不是引用。
我实际上会在我可能想要调试的模块中使用 ostream 实例。请注意,此类型没有默认构造函数,您必须将指针传递给流缓冲区,但该指针可以为 null。现在,当您/如果要捕获模块的输出时,只需使用 rdbuf()
将流缓冲区附加到它。这个流缓冲区可以是 std::cout 的流缓冲区,但它也可以是一个std::stringbuf
或std::filebuf
,或者一些自动将输出重定向到某个窗口的自写的。需要注意的是:没有流缓冲区的输出将设置故障位(甚至坏位?),因此您必须在更改流缓冲区后对输出流调用clear()
。另请注意,您必须手动管理此流缓冲区和引用它的流的生存期,不涉及所有权转让和自动清理。
- 如何在C++中编写 ostream 的向量,它接收所有不同的输出流,如 cout、ostringstream 和 ofs
- 在输出流中插入换行符
- 在类外部重载输入和输出流
- 通用容器的输出流
- 我的动态链接队列在同一输出流中调用时不正确地输出三个返回函数
- 使输出流式处理运算符适用于 boost::variant<std::vector<int>、int、double 的正确方法是什么>
- 获取C++输出流中元素的大小
- 用于了解输入和输出流缓冲区实际工作方式的程序
- 控制多线程程序中的输出流
- 如何调试输出指向成员的指针
- 为什么输出流首选" "而不是""?
- C++ 输出流运算符 <<() 中的字符何时加宽?
- 音频缓冲区列表,用于输出流格式已压缩的 AUHAL 单元
- 如何将值发送到标准输出流并在另一个程序中访问这些值
- 我必须如何将OpenCV输出流到我自己的远程C GUI
- 如何为提升日志和自定义类型定义输出流运算符
- 修改视频帧并将其发送回视频输出流
- 组合输入和输出流
- C++ 中的递增/递减和输出流运算符优先级
- 作为类成员的输出流