• C++ Programming for Financial Engineering
    Highly recommended by thousands of MFE students. Covers essential C++ topics with applications to financial engineering. Learn more Join!
    Python for Finance with Intro to Data Science
    Gain practical understanding of Python to read, understand, and write professional Python code for your first day on the job. Learn more Join!
    An Intuition-Based Options Primer for FE
    Ideal for entry level positions interviews and graduate studies, specializing in options trading arbitrage and options valuation models. Learn more Join!

C++, polymorphism and friendly <<

Joined
3/24/08
Messages
63
Points
18
Suppose I have a base class Domain and derived class DomainFloating.

Domain is abstract, since it defines an interface:
Domain.h:
virtual double deltaCentral() const = 0;
virtual double gammaCentral() const = 0;
virtual double uApprox() const = 0;
virtual double vApprox() const = 0;
and so forth. But it's not pure abstract since it provides its own functions that are to be used by all its derivative classes, DomainFloating and DomainFixed, for example:
Domain.h:
double transform( double S, double t ) const;

double unTransform( double x, double tau ) const;
I've overloaded the << operator for Domain:
Domain.h:
friend ostream& operator<<(ostream& output, const Domain& domain);

and I've also overloaded the << operator for DomainFloating:
DomainFloating.h:
friend ostream& operator << (ostream& output, const DomainFloating& d);
Originally, I was mystified why << for a derived class doesn't chain to the << for a base class, but then it became obvious: these aren't class members, so they have no entries in the vtable and hence don't act polymorphically.

Fine.

But then I have an operational question. I would like to define << for the derived class like this:
PHP:
DomainFloating.cpp:
ostream& operator << ( ostream& output, const DomainFloating& d )
{
   output
      << Domain(d)
      <<  "--- DomainFloating -------------" <<  endl
      <<  "xBarLeft:  "       << d.xBarLeft  <<  endl
      <<  "xBarRight: "       << d.xBarRight <<  endl
      <<  "Nleft:     "       << d.Nleft     <<  endl
      <<  "Nright:    "       << d.Nright    <<  endl
      <<  "--------------------------------" <<  endl;

   return output;  // for multiple << operators.
}
The problem, of course, is that I can't instantiate Domain() because it's abstract. The only way I know how to do this is by doing something retarded, like this:
PHP:
DomainFloating.cpp:
ostream& operator << ( ostream& output, const DomainFloating& d )
{
   output
      <<  d.all       << endl;
      <<  d.the       << endl;
      <<  d.variables << endl;
      <<  d.in        << endl;
      <<  d.the       << endl;
      <<  d.base      << endl;
      <<  d.class     << endl;
      <<  d."Domain"  << endl;
      <<  "--- DomainFloating -------------" <<  endl
      <<  "xBarLeft:  "       << d.xBarLeft  <<  endl
      <<  "xBarRight: "       << d.xBarRight <<  endl
      <<  "Nleft:     "       << d.Nleft     <<  endl
      <<  "Nright:    "       << d.Nright    <<  endl
      <<  "--------------------------------" <<  endl;

   return output;  // for multiple << operators.
}
There must be a more intelligent/convenient way of doing this.

What is it?
 
I don't know the professional way, but I create a virtual "printhelper" function in both Domain and DomainFloating that does the actual printing.

C++:
virtual void printhelper( ostream& os ) const;

The body of this in DomainFloating might call Domain::printhelper( os ).

Then I write a generic << overload that is not a member function; do this once and let polymorphism do the rest.

C++:
ostream& operator<<( ostream& os, const Domain& d )
{
d.printhelper( os );
return os;
}
 
Nice. Kind of round-a-bout, but much more palatable than the brain-dead way of doing this. Thanks!

I wonder WWSMD?

(SM == Scott Meyers) :D
 
I like Doug's solution. But one other way which probably isn't portable is instead of

output << Domain(d)

use

output << *(static_cast<Domain *>(&d))

compiler thinks &d is (Domain *) so it concludes that d is Domain and so uses the desired operator<<.
 
Back
Top