Dev Notes

Software Development Resources by David Egan.

Operator Overloading Custom Output Stream in C++


C++
David Egan

It can be useful to display data from a user-defined type (e.g. an object instantiated from a class) using the std::cout object. This can be achieved by overloading the << operator.

This would allow you to print selected data members in a meaningful way. For example, if you have a class Point which holds data members x and y to represent horizontal and vertical displacement, the following might be a useful way to display a Point object:

Point a(10, 2);

std::cout << a << std::endl;
// Prints "(10, 2)"

You need to set up the insertion operator such that it accepts an std::ostream object on the left and a user-defined type on the right. You achieve this by declaring the overloaded operator as a friend of the class. This allows the function to accept the required parameters, and provides access to private data within the class.

The function is then defined as a free operator -i.e. not a member of a class.

Example

// Point.h
#include <iostream>

class Point {
friend std::ostream& operator<<(std::ostream& os, Point p);
private:
	float m_x;
	float m_y;
public:
	Point(float x, float y);
};
// Point.cpp
#include "Point.h"

// Member function declarations
Point::Point(float x, float y) : m_x(x), m_y(y)
{}
...
std::ostream& operator<<(std::ostream& os, Point p)
{
	// Because this is a friend function, we have access to the object's private data
	os << "(" << p.m_x << ", " << p.m_y << ")";
	return os;
}

Implementation in main.cpp:

...
Point a(99.9, 2.3);
std::cout << a << std::endl;
// Output: (99.9, 2.3)

Don’t Declare the Operator Overload as a Member of the Class

If you declare the operator<< as a non-static data member - i.e. if it is declared in the class, accepting a std::iostream& and Point as parameters, it will cause a compiler error:

g++ -W -Wall -std=c++17 -o bin/main Point.cpp main.cpp
In file included from Point.cpp:1:0:
Point.h:14:53: error: ‘std::ostream& Point::operator<<(std::ostream&, Point)’ must take exactly one argument
  std::ostream& operator<<(std::ostream& os, Point p);

This occurs because:

  • A non-static member method takes an implicit this parameter that is passed as a hidden argument
  • The << operator takes exactly two arguments e.g. for a << b, the arguments are a and b
  • Declared as a member function, there are too many arguments!

It doesn’t make logical sense for the overloaded << operator to be a member function, since in it’s implementation it needs to get data from a passed in object and pass this along to the output stream.

TLDR;

  • Declare the operator<< as a friend of the class.
  • DO NOT define the function as a member of the class - define it as a free function outside the class.
  • The friend declaration ignores the private/public designators

References


comments powered by Disqus