views:

132

answers:

5

C++ purists may want to look away now. You will hate this.

I have been given an open source windows console app that I am merging with a pre-existing, very old, very large windows app of my own. My old program started life as pure C though recently has been tweaked so that it can compile as C++. My program makes extensive use of a my_printf() function which prints text to a window.

The old console app does its printing C++ style via streams (I have never used this type of printing mechanism before).

When converting the console app to work under my system I could manually edit all the lines that do printing so that they use my_printf() instead. But before I embarked on that I thought I'd just check with StackOverflow to see if I was missing a trick. For example I could imagine somehow letting the C++ prints be done via the stream and then somehow scooping the final text somewhere and then calling my_printf() with the result. Might that be possible?

EDIT: please note my knowledge of C++ is extremely limited and I may need to look some things up in order to understand your answers so please use language that facilitates this.

A: 

Subclass std::ostream and make operator << call my_print_f(). You can use internal stringstream in your stream to retrieve string representation of operator << arguments.

Then you'd just have to do find&replace, replacing cout (or whatever stream you directed your output to in the console app) with an instance of your stream class.

Xion
+4  A: 

You might find string streams useful. For example:

std::ostringstream os;
os << "Print " << whatever << data;
my_printf( "%s", os.str().c_str() );

In case you were feeling adventurous, you could write your own streambuf instead that used my_printf underneath, and inject it into the stream object that is currently used in output statements (e.g. std::cout). Be warned that this latter approach might not be trivial, however it would result in almost no changes to existing codebase.

usta
+1 This seems like the most obvious solution to work around the need to use such a fixed API.
Mark B
A: 

Overloading the global operator<< is probably what will solve your problem:

#include <iostream>
#include <cstdio>

static int
my_printf (const char* s)
{
  printf ("my_printf: %s\n", s);
}

namespace std {
    std::ostream& operator<< (std::ostream& out, const char* s)
    {
      my_printf (s);
      return out;
    }
}

int
main ()
{
  std::cout << "hello, world"; // => my_printf: hello, world
  return 0;
}
Vijay Mathew
why did someone downvote this answer?
Mick
-1, This is wrong on quite a few levels. Most damning, it will introduce a surprising namespace dependency. The normal `operator<<` is **not global** . It's `std::operator<<`.
MSalters
@Mick you can up-vote it :-)
Vijay Mathew
@vijay mathew: I am not expert enough to know whether I should :-( ... I liked your answer because it gave example code, but with a downvote I thought that maybe it was flawed.
Mick
It might be illegal to place such overloads into std namespace. Secondly, what if you want to output something other than C strings (`cout << 10 << endl;`)? What if cout is used on user-defined types?
UncleBens
It _is_ illegal to place such overloads in the `std` namespace. And (when discussing other types) there are some operator<< overloads that are members of `std::ostream`, not free functions.
MSalters
MSalters
+7  A: 

There's indeed a trivial trick. But C++ impurists will hate the fact that C++ has a pure solution ;)

std::ostream is responsible for formatting, but not printing itself. That's handled by std::streambuf. std::cout combines a std::ostream formatter with a std::streambuf-derived object that writes to stdout.

However, you can change the streambuf backing an ostream with ostream::rdbuf(newbuf). As std::cout is just another ostream, you can replace its streambuf too. In this case, you only need to come up with a streambuf-derived class that writes already-formatted output to my_printf(). That should be quite trivial.

MSalters
@Msalters: this solution may indeed be more slick than the example code in usta's answer, but the other answer was easier for me to understand and implement. +1 from me anyway.
Mick
A: 

Something along these lines might be helpful:

http://www.codeproject.com/KB/debug/debugout.aspx

Should be obvious where the meat of it is, so you can make it print via your own systems, or what have you. In theory, you'd need only search for references to std::cout and replace them with references to your own object.

brone