Lec 11: Operators
When you are using overloaded operators, you are actually calling member functions:
#include <iostream>
#include <vector>
#include <string>
using namespace std;
void human_readable_form() {
vector<string> v{"Hello", "World"};
cout << v[0];
v[1] += "!";
}
void member_function_form() {
vector<string> v{"Hello", "World"};
cout.operator<<(v.operator[](0));
v.operator[](1).operator+=("!");
}
void non_member_function_form() {
// Note: there are some operators that can't be written in non-member-function form.
vector<string> v{"Hello", "World"};
operator<<(cout, operator[](v, 0));
operator+=(operator[](v, 1), "!");
}
A Simple Implementation
// ...
class StringVector {
private:
vector<string> data;
public:
StringVector () = default;
StringVector& operator+= (const string& str);
StringVector& operator+= (const StringVector& vec);
// Note: don't use `string& operator[] const (const int& index);`
// Since `const` modifier doesn't allow you to return a
// non-const reference to a member variable
string& operator[] (const int& index);
int size();
};
int StringVector::size()
{
return data.size();
}
// Member function style
StringVector& StringVector::operator+= (const string& str)
{
data.push_back(str);
return *this;
}
StringVector& StringVector::operator+= (const StringVector& vec)
{
data.insert(data.end(), vec.data.cbegin(), vec.data.cend());
return *this;
}
// Non-member function style
string& StringVector::operator[] (const int& index)
{
return data[index];
}
Note: We use const <type>&
here, since:
const
value can't be implicitly converted to non-const
one, so we'd better useconst
- e.g.
strvec += "Hello"
,"Hello"
here isconst
(and alsoconstexpr
) - Use reference to avoid unnecessary copy.
General Rule of Thumb
- Some operators must be implemented as members, e.g.,
[]() -> =
, due to C++ semantics. - Some operators must be implemented as non-members, e.g.,
<
, if you are writing a class for the right-hand side (rhs), not the left-hand side (lhs). - If it's a unary operator, e.g.,
++
, implement it as a member. - If binary operator treats both operands equally (e.g., both unchanged), implement as non-member (maybe friend). Examples:
+
,<
- If binary operator does not treat both operands equally (changes
lhs
), implement as a member (allows easy access tolhs
private members). Examples:+=
friend
modifier
Imagine you have a Fraction
class:
And you want to use cout
to output it. By "General Rule of Thumb", you are writing a class for the rhs (i.e. Fraction
instead of ostream
), you have to use non-member.
ostream& operator<< (ostream& os, const Fraction& f)
{
// Error! `nom` and `denom` are private!
os << f.nom << "/" << f.denom;
return os;
}
However, nom
and denom
are private members in Fraction
, so it seems that you can't use them in non-members without extra modifier(s).
That's why we have to introduce friend
modifier for adding non-member functions to the friends list of the target class.
class Fraction {
private:
int denom;
int nom;
friend ostream& operator<< (ostream& os, const Fraction& f);
};
Const-ness and others
Take operator<<
as example:
-
ostream&
return type, because -
we have to chain
<<
's, soostream
and&
(instead ofvoid
) -
it will change, so non-
const
-
we aren't creating new objects, so
&
-
ostream& os
, because -
it will change, so non-
const
-
const Fraction& f
, because -
it will merely be copied and not change, so
const
Principle of Least Astonishment (POLA)
"If a necessary feature has a high astonishment factor, it may be necessary to redesign the feature".
- Design operators primarily to mimic conventional usage.
- example 1:
+=
returns a reference to the lhs object - counterexample 1: overloading
,
- counterexample 2: overloading
+
forTime
withsec, min, hour, ...
, since we don't know whether+1
is adding a sec or a day, etc - Use nonmember functions for symmetric operators.
- to avoid non-symmetric cases like
"char" + str
: invalidstr + "char"
: valid
- Always provide all out of a set of related operators.
- e.g. Implement all
==, !=, <, >, <=, >=, <=>
(if the class supports) and not just some of them