我试图通过重载流来在c ++中同时写入文件和标准输出
test.h
#pragma once
#include <iostream>
using std::ofstream;
class OutputAndConsole:public ofstream
{
public:
std::string fileName;
OutputAndConsole(const std::string& fileName):ofstream(fileName),fileName(fileName){
};
template <typename T>
OutputAndConsole& operator<<(T var);
};
template <typename T>
OutputAndConsole& OutputAndConsole::operator<<(T var)
{
std::cout << var;
ofstream::operator << (var);
return (*this);
};
Run Code Online (Sandbox Code Playgroud)
TEST.CPP
OutputAndConsole file("output.txt");
file << "test" ;
Run Code Online (Sandbox Code Playgroud)
文件中的输出是
01400930
Run Code Online (Sandbox Code Playgroud)
但在控制台是
test
Run Code Online (Sandbox Code Playgroud)
我调试了它看起来正在进入的代码
_Myt& __CLR_OR_THIS_CALL operator<<(const void *_Val)
Run Code Online (Sandbox Code Playgroud)
我究竟做错了什么?
我不打算评论为什么你的方法不起作用,主要是因为它无法修补以正常工作.主要的问题是你不能使用你的流将它传递给预期std::ostream&
仍然写入两个流的东西.但是,有一个相对简单但不一定明显的方法来实现您真正想要的东西:您将派生一个新的流缓冲区,即派生自的类std::streambuf
,并覆盖它overflow()
和sync()
函数.以下是简单演示的完整代码:
#include <streambuf>
struct teebuf
: std::streambuf
{
std::streambuf* sb1_;
std::streambuf* sb2_;
teebuf(std::streambuf* sb1, std::streambuf* sb2)
: sb1_(sb1), sb2_(sb2) {
}
int overflow(int c) {
typedef std::streambuf::traits_type traits;
bool rc(true);
if (!traits::eq_int_type(traits::eof(), c)) {
traits::eq_int_type(this->sb1_->sputc(c), traits::eof())
&& (rc = false);
traits::eq_int_type(this->sb2_->sputc(c), traits::eof())
&& (rc = false);
}
return rc? traits::not_eof(c): traits::eof();
}
int sync() {
bool rc(true);
this->sb1_->pubsync() != -1 || (rc = false);
this->sb2_->pubsync() != -1 || (rc = false);
return rc? 0: -1;
}
};
#include <fstream>
#include <iostream>
int main()
{
std::ofstream fout("tee.txt");
teebuf sbuf(fout.rdbuf(), std::cout.rdbuf());
std::ostream out(&sbuf);
out << "hello, world!\n";
}
Run Code Online (Sandbox Code Playgroud)
显然,tee-stream的创建可以很好地打包,但这看起来完全不重要.重要的是,可以为IOStreams创建自定义目标(或源),并且它不涉及任何继承的尝试std::ostream
.从std::ostream
(或std::istream
)继承的唯一原因是使用自定义流缓冲区初始化流更容易.
Run Code Online (Sandbox Code Playgroud)ofstream::operator << (var);
它ofstream::operator<<
用作合格的函数调用。您要强制函数查找找到ofstream
; 的成员函数;成员的最佳匹配是的匹配void*
,而char*
打印实际字符串内容的专业化是一个自由函数(即不是成员函数)。
如果使用,也会发现同样的问题cout
:
std::cout.operator<<(var);
Run Code Online (Sandbox Code Playgroud)
这可以做到:
static_cast<ofstream&>(*this) << var;
Run Code Online (Sandbox Code Playgroud)
因为您仍在使用普通运算符语法(具有所有的重载分辨率),但是使用ofstream
LHS操作数作为。
我实际上还没有测试过。
顺便说一句,为了符合此约定,您也 operator<<
应该是一个自由函数。
所以:
struct OutputAndConsole : std::ofstream
{
OutputAndConsole(const std::string& fileName)
: std::ofstream(fileName)
, fileName(fileName)
{};
const std::string fileName;
};
template <typename T>
OutputAndConsole& operator<<(OutputAndConsole& strm, const T& var)
{
std::cout << var;
static_cast<std::ofstream&>(strm) << var;
return strm;
};
Run Code Online (Sandbox Code Playgroud)
我还自由地进行了一些小的语法调整。