In the end, it’s overloading a function...
Apart from the “friend” business, it’s just another overloaded “operator<<“ function:
ostream& operator<< (ostream& os, int &);
ostream& operator<< (ostream& os, float &);
ostream& operator<< (ostream& os, double &);
ostream& operator<< (ostream& os, char &);
ostream& operator<< (ostream& os, long &);
//… all the system-defined ones …
ostream& operator<< (ostream& os, cube &c);
We add one more, just as we saw before (ok, so it’s a non-member function, it’s not a function but an operator, but the principle holds).