输出到几个ostreams的类(文件和控制台)

Jes*_*nds 3 c++ inheritance ostream

是的,我甚至不确定如何正确地制定这个; 我觉得这是一个涉及的问题.我相信有人可以帮助我.

这就是我想要做的:

  1. 有一个我可以发送东西的课程,就像这样.

    icl << "Blah blah blah" << std::endl;
    
    Run Code Online (Sandbox Code Playgroud)
  2. 我希望能够继承std :: basic_ostream的.attach()类.

  3. 然后,这些类将能够以自己的方式格式化输出.有人可能会添加一个时间戳并写入日志,另一个可能会将其写入控制台,另一个可能会在游戏中显示它.

有人想让我开始朝着正确的方向前进吗?这是我几乎拥有的想法.

#include <vector>

class OutputMan {
    std::vector<std::basic_ostream&> m_Streams;

public:
    void attach(std::basic_ostream& os) {
        m_Streams.push_back(os);
    }
}
Run Code Online (Sandbox Code Playgroud)

问题1:我需要继承和覆盖发送什么

icl << "Blah!" << std::endl;
Run Code Online (Sandbox Code Playgroud)

到m_Streams中的每个流?

问题2:如何继承std :: basic_ostream并创建一个更改输出的类,例如,在其开头添加时间戳?我也希望这个类输出到一个文件.

Jer*_*fin 5

我想我的做法有点不同.我可能已经做了一些比必要更精细的事情 - 我担心我可能会因为尝试使用新的C++ 11功能而感到沮丧.无论如何,使用代码:

#include <streambuf>
#include <fstream>
#include <vector>
#include <iostream>
#include <initializer_list>

namespace multi { 
class buf: public std::streambuf {
    std::vector<std::streambuf *> buffers;
public:
    typedef std::char_traits<char> traits_type;
    typedef traits_type::int_type  int_type;

    buf(std::vector<std::ofstream> &buf) {
        for (std::ofstream &os : buf)
            buffers.push_back(os.rdbuf());
    }

    void attach(std::streambuf *b) { buffers.push_back(b); }

    int_type overflow(int_type c) {
        bool eof = false;
        for (std::streambuf *buf : buffers) 
            eof |= (buf -> sputc(c) == traits_type::eof());
        return eof ? traits_type::eof() : c;
    }   
};

class stream : public std::ostream { 
    std::vector<std::ofstream> streams;
    buf outputs;
public:   
    stream(std::initializer_list<std::string> names)
        : streams(names.begin(), names.end()), 
          outputs(streams), 
          std::ostream(&outputs) 
    { }
    void attach(std::ostream &b) {
        outputs.attach(b.rdbuf());
    }
};
}

int main() { 
    multi::stream icl({"c:\\out1.txt", "c:\\out2.txt"});
    icl.attach(std::cout);

    icl << "Blah blah blah" << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,这已经接受了操纵器(它应该适用于任何操纵器,而不仅仅是std::endl).如果要写入多个文件(可以/可以作为fstream打开的东西),您可以根据需要在构造函数中指定尽可能多的名称(当然,在系统强加的范围内).喜欢的事情std::cout,并std::cerr为你不一定有一个文件名,你可以使用attach你原本打算.

我想我应该补充说,我对此并不完全满意.它会采取一些相当严重的重写做到这一点,但经过一番思考,我认为"正确"的方式很可能是对multi::stream的构造函数是不是一个可变参数模板,所以你可以这样做:multi::stream icl("c:\\out1.txt", std::cout);,它将根据其类型理清如何使用每个参数.我可能会更新这个答案,以便很快包含该功能.

至于第二个问题,我已经写了另一个涵盖基本概念的答案,但可能有点过于精细,所以你关心的部分可能会在洗牌中丢失,可以这么说 - 它有处理你并不真正关心的行长度的相当多的逻辑(但确实产生了具有指定前缀的每个输出行,如你所愿).