TB 5.2 - Friend Functions
If you're reading this and wondering why the naming convention changed, it's because this is around the time when I stopped showing up to classes. Yay!
It's also around the time I discovered that the textbook is actually a better resource for my learning than Salma's lectures. No shade to Salma (she wrote the textbook after all)
issue! operator overloading when LHS is not an object of same class
Consider the following:
Complex z(3, 4);
cout << z;
This exhibits the following issues:
ostream(the class thatcoutis a part of) does not take typeComplexas a data type, and we cannot redefine it to do so becauseostreamis part of the C++ standard library.- There is no
operator<<function we can call because the data type that it would be called on is not an object that we can redefine. For the above example, this means thatcoutcannot be a member of the functionComplex.
We also can't just haveoperator<<be a non-member function (meaning it is defined outside of the class), takingostreamandComplexobjects as parameters, because this prevents us from accessing the private members of theComplexclass.
The solution, then, is to use a friend function of the Complex class.
friend functions
To alleviate the issue we encountered above, we can use a friend function.
A Friend Function is a non-member function that:
- has access to private members of the class in which it is declared a friend, as if they were public members
- allows left operand (LHS) to be a different type
example
We can declare operator<< as a friend function of the object Complex. This will have the following syntax:
class Complex {
// ...
friend ostream& operator<<(ostream& os, const Complex& rhs);
}
Or more generally:
class Complex {
// ...
friend <<return type>> operator<<(<<parameter list>>);
};
Notes:
<<parameter list>>should receive both:- the LHS
coutas an object of theostreamclass - the RHS
zas an object of theComplexclass
- the LHS
- all streams (e.g.
istream,ostream,fstream, etc.) are passed by reference to avoid making a copy of those objects; compiler returns a compiler error if we return a stream by value. - the return type should be
ostream&, i.e. a reference to theostreamobject that was originally passed into the function, as this allows us to chain multipleoperator<<'s together- think of
cout << "hello" << " world" << endl;
- think of
zis passed as aconstbecause we do not want to modify theComplexobject when we are simply trying tocoutits members- we are not making the function itself a
const, because the function is not part of any class; it is a non-member function.- we aren't allowed to do this because
constprevents us from altering the values inside of the object that the function is called on, but since it is not called on any specific object, we are not able to edit them anyway. - instead, we add
constto the parameters passed into the function.
- we aren't allowed to do this because
example of a friend function
take the Complex class from L13 and L14. If we want to define a operator<< function, this is how we would do it:
#include <iostream>
using namespace std;
class Complex {
private:
double real;
double img;
public:
Complex() { // the constructor
real = 0;
img = 0;
}
Complex(double r, double i) {
// the constructor if we pass in the right params
real = r;
img = i;
}
// overloading the << operator
friend ostream& operator<<(ostream& os, const Complex& rhs);
// return reference to ostream object
// pass in ostream reference (not const bc we are modifying it)
// also pass in unmodifiable Complex reference to get data members
};
ostream& operator<<(ostream& os, const Complex& rhs) {
os << "(" << rhs.real << ", " << rhs.img << ")" << endl;
return os; // return the same stream object
}
int main(void) {
Complex z(3.0, 4.0);
cout << "z is " << z << endl;
return 0;
}
Notes:
- since the friend function is not a member of the class, we do not need
Complex::to go before the function name when defining it outside of the class