Help with operator overloading of <<

Discussion in 'C++' started by winbatch, Feb 13, 2005.

  1. winbatch

    winbatch Guest

    Hi,
    I'm trying to play with classes and I'm having trouble with a
    theoretical
    problem.

    I've create a 'Log' class, who creates and writes to log files. I was
    able
    to overload the << operator so that I could write to my log as follows:

    Log logOne("log.txt", true, "\n" );
    logOne<<"BLAH"<<"BLAH2";

    In the constructor, the 'true' refers to having the log class write out
    a
    datetime stamp of each log entry, while the '\n' indicates how to
    terminate
    the log line.

    The problem is that when I use the syntax about (<<"A"<<"B" ), etc, it
    ends
    up writing multiple lines because the << function is getting called
    each
    time. What I would like to do is have A and B be concatenated into one
    string and then do the actual call to write the log line once. How do I
    know
    if I am the 'LAST' item being sent to the << so that I can store the
    intermediate values and not write it out unless I am last?

    Here is my function: (quite simple)
    Log & operator << (string a)
    {
    writeLog(a);
    return *this;
    }


    Thanks in advance...
    winbatch, Feb 13, 2005
    #1
    1. Advertising

  2. winbatch

    Chris Theis Guest

    "winbatch" <> wrote in message
    news:...
    > Hi,
    > I'm trying to play with classes and I'm having trouble with a
    > theoretical
    > problem.
    >
    > I've create a 'Log' class, who creates and writes to log files. I was
    > able
    > to overload the << operator so that I could write to my log as follows:
    >
    > Log logOne("log.txt", true, "\n" );
    > logOne<<"BLAH"<<"BLAH2";
    >
    > In the constructor, the 'true' refers to having the log class write out
    > a
    > datetime stamp of each log entry, while the '\n' indicates how to
    > terminate
    > the log line.
    >
    > The problem is that when I use the syntax about (<<"A"<<"B" ), etc, it
    > ends
    > up writing multiple lines because the << function is getting called
    > each
    > time.


    Operator << must (!) be called here twice because you call it twice ;-) So
    that behavior absolutely makes sense.

    > What I would like to do is have A and B be concatenated into one
    > string and then do the actual call to write the log line once. How do I
    > know
    > if I am the 'LAST' item being sent to the << so that I can store the
    > intermediate values and not write it out unless I am last?
    >
    > Here is my function: (quite simple)
    > Log & operator << (string a)
    > {
    > writeLog(a);
    > return *this;
    > }
    >


    Without seeing the writeLog(a) function this code snippet is not worth very
    much, but there are some things that are visible right away. First of all
    you should pass a const string reference instead of the string object. This
    has nothing to do with your problem but you´ll save yourself unnecessary
    copies of the string object.
    Despite this your problem is located in the writeLog function which I assume
    will look something like this:

    void writeLog( string Text ) {
    cout << m_Date << " " << Text << endl;
    }

    And here it is - the end of line manipulator endl. Just skip it and all
    strings are going to be output on the same line. However, you should
    terminate the line yourself sending the endl or "\n" to the stream after the
    last thing you want to output. In principle it works just like the normal
    cout stream.

    Cheers
    Chris
    Chris Theis, Feb 13, 2005
    #2
    1. Advertising

  3. winbatch

    Dan Hoffman Guest

    Chris,

    I don't have an endl in my writeLog function. The reason is that the
    constructor takes a parameter which will be the EOL for the log. The reason
    for this is that I have another class which contains multiple logs and I
    just send it a string and it will call the writeLog of each of the Log
    objects inside. Since certain logs will have different terminators, I
    didn't want to have to deal with this when I passed the string to be logged,
    but rather it be part of the Log object itself.

    I realize that the << is being called twice, and that's exactly the problem.
    I only want the log to be written to the file when I'm on the LAST call to
    the <<. All previous calls should simply append the string to some buffer
    so that when I hit the last call to <<, I can write out my buffer (with the
    last string included).

    This is the writeLog function for your reference. Regarding your advice
    about const, I have taken your advice.

    void Log::writeLog( const string &logLine )
    {
    content=logLine;
    if ( !out->is_open() )
    throw DHException( 3, "Attempt to write to log file [", fileName.c_str(),
    "] without opening first!");

    if ( includeDate )
    {
    current.now();
    content = Date::getFormattedDate( current ) +">" + content + suffix;
    }


    out->write( content.c_str(), content.size() );
    out->flush();

    if ( !out->is_open() )
    throw DHException ( 3, "Could not write to log file [", fileName.c_str(),
    "] !");

    }

    "Chris Theis" <> wrote in message
    news:cunsja$iki$...
    >
    > "winbatch" <> wrote in message
    > news:...
    >> Hi,
    >> I'm trying to play with classes and I'm having trouble with a
    >> theoretical
    >> problem.
    >>
    >> I've create a 'Log' class, who creates and writes to log files. I was
    >> able
    >> to overload the << operator so that I could write to my log as follows:
    >>
    >> Log logOne("log.txt", true, "\n" );
    >> logOne<<"BLAH"<<"BLAH2";
    >>
    >> In the constructor, the 'true' refers to having the log class write out
    >> a
    >> datetime stamp of each log entry, while the '\n' indicates how to
    >> terminate
    >> the log line.
    >>
    >> The problem is that when I use the syntax about (<<"A"<<"B" ), etc, it
    >> ends
    >> up writing multiple lines because the << function is getting called
    >> each
    >> time.

    >
    > Operator << must (!) be called here twice because you call it twice ;-) So
    > that behavior absolutely makes sense.
    >
    >> What I would like to do is have A and B be concatenated into one
    >> string and then do the actual call to write the log line once. How do I
    >> know
    >> if I am the 'LAST' item being sent to the << so that I can store the
    >> intermediate values and not write it out unless I am last?
    >>
    >> Here is my function: (quite simple)
    >> Log & operator << (string a)
    >> {
    >> writeLog(a);
    >> return *this;
    >> }
    >>

    >
    > Without seeing the writeLog(a) function this code snippet is not worth
    > very
    > much, but there are some things that are visible right away. First of all
    > you should pass a const string reference instead of the string object.
    > This
    > has nothing to do with your problem but you´ll save yourself unnecessary
    > copies of the string object.
    > Despite this your problem is located in the writeLog function which I
    > assume
    > will look something like this:
    >
    > void writeLog( string Text ) {
    > cout << m_Date << " " << Text << endl;
    > }
    >
    > And here it is - the end of line manipulator endl. Just skip it and all
    > strings are going to be output on the same line. However, you should
    > terminate the line yourself sending the endl or "\n" to the stream after
    > the
    > last thing you want to output. In principle it works just like the normal
    > cout stream.
    >
    > Cheers
    > Chris
    >
    >
    Dan Hoffman, Feb 13, 2005
    #3
  4. winbatch

    GB Guest

    winbatch wrote:
    > I've create a 'Log' class, who creates and writes to log files. I was
    > able
    > to overload the << operator so that I could write to my log as follows:
    >
    > Log logOne("log.txt", true, "\n" );
    > logOne<<"BLAH"<<"BLAH2";
    >
    > In the constructor, the 'true' refers to having the log class write out
    > a
    > datetime stamp of each log entry, while the '\n' indicates how to
    > terminate
    > the log line.
    >
    > The problem is that when I use the syntax about (<<"A"<<"B" ), etc, it
    > ends
    > up writing multiple lines because the << function is getting called
    > each
    > time. What I would like to do is have A and B be concatenated into one
    > string and then do the actual call to write the log line once. How do I
    > know
    > if I am the 'LAST' item being sent to the << so that I can store the
    > intermediate values and not write it out unless I am last?


    Instead of writing the timestamp from within the insertion function,
    require that it be added explicitly. You can do this by defining your
    own timestamp stream manipulator, logstamp, which you would then use
    like this:

    log << logstamp << "blah1" << "blah2" << std::endl;


    I have done something similar to this. Another thing I have done to make
    the log thread-safe is to take advantage of the C++ property that
    temporary objects are guaranteed not to be destroyed until the entire
    expression in which it appears is evaluated. I take advantage of this by
    acquiring a log mutex in logstamp's constructor and releasing it in its
    destructor. That way the entire string of insertions is guaranteed to be
    atomic. No need for printf-style output mechanism. Details are
    off-topic, though.

    Gregg
    GB, Feb 14, 2005
    #4
  5. winbatch

    Chris Theis Guest

    "Dan Hoffman" <> wrote in message
    news:w0PPd.6442$...
    > Chris,
    >
    > I don't have an endl in my writeLog function. The reason is that the
    > constructor takes a parameter which will be the EOL for the log. The

    reason
    > for this is that I have another class which contains multiple logs and I
    > just send it a string and it will call the writeLog of each of the Log
    > objects inside. Since certain logs will have different terminators, I
    > didn't want to have to deal with this when I passed the string to be

    logged,
    > but rather it be part of the Log object itself.
    >
    > I realize that the << is being called twice, and that's exactly the

    problem.
    > I only want the log to be written to the file when I'm on the LAST call to
    > the <<. All previous calls should simply append the string to some buffer
    > so that when I hit the last call to <<, I can write out my buffer (with

    the
    > last string included).
    >
    > This is the writeLog function for your reference. Regarding your advice
    > about const, I have taken your advice.
    >
    > void Log::writeLog( const string &logLine )
    > {
    > content=logLine;
    > if ( !out->is_open() )
    > throw DHException( 3, "Attempt to write to log file [", fileName.c_str(),
    > "] without opening first!");
    >
    > if ( includeDate )
    > {
    > current.now();
    > content = Date::getFormattedDate( current ) +">" + content + suffix;
    > }
    >
    >
    > out->write( content.c_str(), content.size() );
    > out->flush();
    >
    > if ( !out->is_open() )
    > throw DHException ( 3, "Could not write to log file [",

    fileName.c_str(),
    > "] !");
    >
    > }
    >
    > "Chris Theis" <> wrote in message
    > news:cunsja$iki$...
    > >
    > > "winbatch" <> wrote in message
    > > news:...
    > >> Hi,
    > >> I'm trying to play with classes and I'm having trouble with a
    > >> theoretical
    > >> problem.
    > >>
    > >> I've create a 'Log' class, who creates and writes to log files. I was
    > >> able
    > >> to overload the << operator so that I could write to my log as follows:
    > >>
    > >> Log logOne("log.txt", true, "\n" );
    > >> logOne<<"BLAH"<<"BLAH2";
    > >>
    > >> In the constructor, the 'true' refers to having the log class write out
    > >> a
    > >> datetime stamp of each log entry, while the '\n' indicates how to
    > >> terminate
    > >> the log line.
    > >>
    > >> The problem is that when I use the syntax about (<<"A"<<"B" ), etc, it
    > >> ends
    > >> up writing multiple lines because the << function is getting called
    > >> each
    > >> time.

    > >
    > > Operator << must (!) be called here twice because you call it twice ;-)

    So
    > > that behavior absolutely makes sense.
    > >
    > >> What I would like to do is have A and B be concatenated into one
    > >> string and then do the actual call to write the log line once. How do I
    > >> know
    > >> if I am the 'LAST' item being sent to the << so that I can store the
    > >> intermediate values and not write it out unless I am last?
    > >>
    > >> Here is my function: (quite simple)
    > >> Log & operator << (string a)
    > >> {
    > >> writeLog(a);
    > >> return *this;
    > >> }
    > >>

    > >


    Hi Dan,

    I personally would find it clearer to implement the date/time stamp as a
    manipulator as already recommended in another posting. Otherwise you could
    implement your log to buffer the strings until your own user supplied endl -
    manipulator signals a flush.

    Cheers
    Chris
    Chris Theis, Feb 14, 2005
    #5
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. John Smith
    Replies:
    2
    Views:
    419
    Ivan Vecerina
    Oct 6, 2004
  2. Replies:
    11
    Views:
    728
    James Kanze
    May 16, 2007
  3. hurcan solter
    Replies:
    3
    Views:
    728
    Cholo Lennon
    Aug 29, 2007
  4. Replies:
    11
    Views:
    558
  5. Replies:
    2
    Views:
    311
Loading...

Share This Page