В лекции 9 рассматривался следующий пример конструктора класса Date.
Date(int d, int m, int y)
{
    this->d = d;
    this->m = m;
    this->y = y;
}
Данная реализация является упрощённой («как в Паскале»). В C++ для инициализации полей в конструкторе используются списки инициализации.
class Date
{
    int d, m, y;
public:
    Date(int d, int m, int y) : d(d), m(m), y(y) {}
};
Здесь
d(d), m(m), y(y)— список инициализации.
Конструкция d(d) означает поле(аргумент конструктора).
Если список инициализации не используется (как в первой версии), то в случае
полей классовых типов (например, string) всё равно вначале будут вызваны их
конструкторы, а затем в теле конструктора класса значения полей будут перезаписаны
на основе аргументов конструктора. То есть выполняется двойная работа.
Для больших классов часто разносят описание и реализацию всех функций-членов для улучшения обозримости класса, возможно оставляя определение таких мелких объектов, как конструктор в данном примере.
Как было сказано на прошлой лекции, бинарные операции можно перегружать двумя способами:
При перегрузке бинарной операции, очень важно правильно ответить на вопрос:
Как выбрать между функцией-членом и внешней функцией?
Ключевым моментом этого выбора является то, что функция-член имеет доступ к закрытым полям класса. Для многих операций думать над этим не нужно, а нужно знать стандартный подход, который является наиболее разумным в большинстве случаев.
Рассмотрим перегрузку операции сравнения на равенство на примере класса Date
из лекции 9.
class Date
{
    int d, m, y;
public:
    //bool operator==(Date d1, Date d2) типичная ошибка
    bool operator==(Date const & other)
    {
        return d == other.d &&
               m == other.m &&
               y == other.y;
    }
};
Замечания. Если операция бинарная, то у нее будет один аргумент (в случае, когда операция определена функцией-членом). Если класс этого аргумента совпадает с текущим классом, то у нас есть доступ к закрытым полям объекта-аргумента.
Аргумент оператора правильнее передавать по ссылке на константу.
Это общее правило C++: сначала формальный параметр описывается
как ссылка на константу, затем, при необходимости, из объявления параметра
убирается const. В последнюю очередь стоит подумать о передаче объекта по
значению (это нужно довольно редко).
Должен ли operator<<(>>) быть функцией-членом?
Ответ: нет, он должен быть внешней функцией т.к cout — объект существующего
класса, в который мы не можем добавить перегрузку для вывода объекта нашего
нового класса.
Если operator<<(>>) должен быть внешней функцией, тогда как получить доступ к
полям класса Date?
Для решения это проблемы operator<< обычно объявляется другом класса:
в начале заголовка добавляется ключевое слово friend.
/* date.h */
class Date
{
    int d, m, y;
public:
    // …
    friend
    ostream & operator<<(ostream & os, Date const & d);
};
/* date.cpp */
ostream & operator<<(ostream & os, Date const & d)
{
    os << d.d << '.' << d.m << '.' << d.y << '\n';
    return os;
}
Функция operator<< должна возвращать ссылку на полученный объект потока для
допустимости цепочек типа cout << d1 << d2;
Операция чтения из потока определяется аналогичным образом, только вместо ostream используется istream.
Т.к. operator<< небольшой, то его лучше сделать inline. Перенесем реализацию
в заголовочный файл.
/* date.h */
class Date {
    int d, m, y;
public:
    // …
    friend
    ostream & operator<<(ostream & os, Date const & d)
    {
        return os << d.d << '.' << d.m << '.' << d.y << '\n';
    }
};
Если друг класса определен прямо в классе, то он остается внешней функцией и
становится inline.
Пусть @ ∈ {+, -, *, /}.
Обычно определяют пару функций: operator@=, operator@.
В таком случае operator@= определяется как функция-член, а operator@ — как
внешняя функция.
Операция @= называется присваивающей формой операции @.
Рассмотрим перегрузку арифметических операций на примере класса BigInteger.
class BigInteger {
    int data[1024];
public:
    BigIntiger & operator+=(BigInteger cons & other)
    {
        // Цикл по data: суммирование и перенос
        // Возвращаем ссылку на себя
        return *this;
    }
};
BigInteger operator+(BigInteger const & bi1, BigInteger const & bi2)
// функция не может возвращать ссылку, потому возвращает новый объект
{
    BigInteger res(bi1);  // копия bi1
    res += bi2;           // res хранит bi1 + bi2
    return res;
}
Так как ссылки на локальные переменные запрещены, а аргументы + должны остаться
неизменными, сумму они хранить не могут, то нам не на что возвращать ссылку и
мы возвращаем новый объект. При этом происходит копирование объекта из кадра
стека функции operator+ в кадр стека вызывающей его функции, что может
иметь чувствительные накладные расходы.
Поскольку @= является inline, дополнительных расходов на её вызов не возникает.