1

I'm trying to create a report/logger Class in c++.

I want to have in the main an object called Report and apply to this class the operator << to write to file multiple strings just like ofstream does.

So instead of using the following code:

  ofstream myfile ("d://example.txt");
  if (myfile.is_open())
  {
    myfile << "This is a line.\n" << "Heya!!!" << endl;
    myfile.close();
  }

I would like to have something like the following :

  Report rLogger ("d://example.txt"); // Report C'tor (const string& s)
  logger << "This is a line.\n" << "Heya!!!" << endl;
// the destructor of rLogger will close the file when it dies...

I just can't find out a way to write the operator << as a member function which seems exactly what I need here. The only way I can use the operator << is as friend which isn't helpful in this case. Can someone give me an idea how can I implement it as above?

Thank in advance, Guy

4

5 回答 5

4

Try the following:

class Report {
    public:
        Report() {}

        Report(std::string _str) : stream(_str) {}

        Report& operator <<(std::string str) {
            if (stream.is_open())
                stream << str;

            return *this;
        }

        ~Report() { stream.close(); }

        std::ofstream stream;
};

For the above you must also include the <string> header.

于 2013-01-26T18:14:11.840 回答
4

It seems you want to create a stream-like type. Do not create a stream like type by overloading the output operator <<! The way to create a new stream-like type is to create a stream buffer (i.e., a type derived from std::streambuf) and use this to initialize an std::ostream object, probably by using std::ostream as a base class.

The other approaches for overloading operator<<() won't work for manipulators like std::endl: the manipulator std::endl is a function template and for deducing it template arguments when being used it is necessary to have an overload which can be used to deduce the type correct. The std::ostream class does this by providing suitable special overloads.

I realize that this isn't answering your question about how to overload operator<<() as a member but I think it is the wrong approach and it will probably yield better results changing the way the problem is addressed. I would provide more detail on how to create the corresponding classes but there isn't sufficient context given.

于 2013-01-26T18:58:25.240 回答
2

It seems like your problems stem from needing to insert different types to your report, such as "Heya!!!" or std::endl.

One flexible solution is to do this with templates.

You may implement it as a member function, where the Report is pointed to by this:

class Report {
    public:

        template < typename T >
        Report& operator <<( const T &data ) { ... }

};

Or as a friend function, where there is no this and Report is instead explicitly mentioned and named:

class Report {
    public:

        template < typename T >
        friend Report& operator <<( Report &r, const T &data ) { ... }

};

Or as a stand-alone function, if the Report has enough public methods to do the job.

template < typename T >
Report& operator <<( Report &r, const T &data ) { ... }
于 2013-01-26T18:40:22.460 回答
1

To implement it as a member function and be able to concatenate several streams you just have to return a reference to the object at the end of the function, e.g.:

class Report {
public:

    // ...

    Report& operator<<(const char *text) {
        // write text to file...

        return *this;
    }

};

Here is a very simple example that prints to standard output instead of a file: http://codepad.org/S8QeJZ1x

于 2013-01-26T18:31:41.110 回答
1

If all you want is to make sure the file is closed after use, class Report is unnecessary. std::ofstream's destructor already closes its file.

The other answers so far, which try to define a templated operator<< have a problem: They won't work with some manipulators including std::endl, since it's actually a function template, and the compiler can't figure out what sort of instantiation it should use.

If the purpose of class Report is to add or modify something in the data going through, that's more easily and more correctly done by defining your own streambuf. This article by James Kanze describes how to do that.

于 2013-01-26T19:00:08.367 回答