为了记录目的而重载cout?

时间:2015-10-27 10:15:06

标签: c++ iostream

我想定义类似新cout的东西,我可以使用它来记录我的数据:

some_type cout2( Message_type message ){
    cout << message;
    logfile.save(message);
}

所以我将用它

cout2 << "some message" << endl;

到目前为止,我无法确定上述代码的确如何。

感谢您的帮助。

6 个答案:

答案 0 :(得分:2)

您可以创建自己的记录器,如:

class Logger {
public:
  Logger(std::string const& filename)
    : stream_(filename, std::ofstream::out | std::ofstream::app)
  {
    if (!stream_) {
      // Error...
    }
  }
  Logger& operator<<(std::string const& str) {
    std::cout << str;
    stream_ << str;
    return *this;
  }
private:
  std::ofstream stream_;
};

答案 1 :(得分:2)

一般来说,C ++标准库中的类不是为了派生而设计的,对于流类来说也是如此。

恕我直言,最好在cout2对象上指定您需要的方法,然后:

  • 设计一个包含ostream&对象的类,在ctor
  • 中初始化
  • 将实际输出委托给该内部对象
  • 在您的方法中执行您需要的任何日志

您应该使用模板operator <<来轻松处理std::ostream可以处理的任何类。

class LogStream {
    std::ostream& out;
    Logfile logfile;

    LogStream(std::ostream& out, /* param for logfile initialization */ ...)
        : out(out), logfile(...) {}
    ... // other useful methods for state
};
template<typename T>
LogStream& operator << (LogStream& out, T val) {
    out.out << message;
    // should first test whether T is  manipulator, and choose whether and how it should be logged
    logfile.save(message);
}

答案 2 :(得分:2)

您不想修改getAnnualIncome()

相反,您希望创建一个专门的for (int index = 0; index < employee.length; ++index) { System.out.printf(employee[index].getName() + "\t\t" + "£%.2f %n", employee[index].getAnnualIncome()); //error message appears here ^^ 'method is undefined in 'Personnel' } ,它写入两个缓冲区而不是一个缓冲区。例如;

std::cout

然后你需要创建一个使用这种缓冲区的专用std::streambuf

#include <streambuf>
template <typename char_type,
          typename traits = std::char_traits<char_type> >
class basic_teebuf:
    public std::basic_streambuf<char_type, traits>
{
public:
    typedef typename traits::int_type int_type;

    basic_teebuf(std::basic_streambuf<char_type, traits> * sb1,
                 std::basic_streambuf<char_type, traits> * sb2)
      : sb1(sb1)
      , sb2(sb2)
    {
    }

protected:      // override virtuals inherited from std::basic_streambuf
    virtual int sync()
    {
        int const r1 = sb1->pubsync();
        int const r2 = sb2->pubsync();
        return r1 == 0 && r2 == 0 ? 0 : -1;
    }

    virtual int_type overflow(int_type c)
    {
        int_type const eof = traits::eof();

        if (traits::eq_int_type(c, eof))
        {
            return traits::not_eof(c);
        }
        else
        {
            char_type const ch = traits::to_char_type(c);
            int_type const r1 = sb1->sputc(ch);
            int_type const r2 = sb2->sputc(ch);

            return
                traits::eq_int_type(r1, eof) ||
                traits::eq_int_type(r2, eof) ? eof : c;
        }
    }

private:
    std::basic_streambuf<char_type, traits> * sb1;
    std::basic_streambuf<char_type, traits> * sb2;
};

typedef basic_teebuf<char> teebuf;

以上所做的就是创建一个使用我们专用缓冲区的专用ostream,后者又使用两个缓冲区。

现在,我们的#include <ostream> class teestream : public std::ostream { public: // Construct an ostream which tees output to the supplied // ostreams. teestream(std::ostream & o1, std::ostream & o2); private: teebuf tbuf; }; teestream::teestream(std::ostream & o1, std::ostream & o2) : std::ostream(&tbuf) , tbuf(o1.rdbuf(), o2.rdbuf()) { } 需要使用两个流进行初始化。例如

std::ostream

这样做的好处是所有流插入(运算符teestream)都可以与我们的#include <fstream> #include <iostream> // include the preceding definition of teestream here int main() { std::ofstream logfile("hello-world.log"); teestream tee(std::cout, logfile); // tee is now a stream that writes the same output to std::cout and logfile tee << "Hello, world!\n"; return 0; } 一起使用 - 即使对于版本过载的类也是如此。

<<返回时,流也将干净地关闭。

我已将特定的teestream编写为模板(main()是名为streambuf的模板化类的特化。一般来说,对流做同样的事情可能会更好(使用std::streambuf也是模板化std::basic_streambuf的特化的事实)。我将这种概括作为一种练习。

答案 3 :(得分:0)

我已经看到的基于这个想法的日志记录系统看起来像这样:

#define MY_PRINT(x, ...) \
        { \
            fprintf(logFile, x, ##__VA_ARGS__); \
            fflush(acuLogFile); \
        }

你会像以下一样使用它:

MY_PRINT("this is just a test\n");

即使这是C语言,它也非常通用,也适用于C ++。

您只需在代码中的任何位置使用新定义的打印功能。

答案 4 :(得分:0)

也许你应该有一个带有.log()方法的基于实例的记录器,根据实现可以记录到文件,写入stdout等,而不是试图从std命名空间重载自由函数?

你的意图会更清晰,更加面向对象。

事实上我最近写的一个非常棒的切割事件记录器的here is an example,如果这有助于你理解我所谈论的那种事情。我的设计允许依赖注入,以及保持无聊决定如何将某些内容格式化为输出以及它应该在记录器中的位置(stdout或文件等)。

答案 5 :(得分:0)

当然你可以定义自己的cout。 首先,你需要一个可以处理&lt;&lt;&lt;&lt;运算符并包含一个fstream和一个ostream(如cout)。

class logstream
{
private:
    fstream *filestream;
    ostream *cout;

public:
    logstream(fstream* filestream, ostream* cout)
    {
        this->cout = cout;
        this->filestream = filestream;
    }

    string operator<< (char* s)
    {
        *cout << s;
        *filestream << s;
        return s;
    }
};

要使用它,只需使用cout和fstream初始化它。

fstream lout = fstream("Filename", ios::app);
logstream cout = logstream(&lout, &std::cout);

现在你有你想要的东西。

cout << "message";

编辑:不要忘记包括

#include <iostream>
#include <fstream>

using namespace std;