printПерегрузка функций и операций

printПримеры перегрузки операций

Перегрузка операции присваивания:
a) для случая, когда перевыделения памяти не происходит
class BadSize {}; // класс для информирования об ошибке
class Vector {
  const int size;
  double *const data;
public:
  Vector &operator=(const Vector &);
  ...
};
Vector & Vector::operator=(const Vector &v)
{ if(size!=v.size)
    throw BadSize();
  for(int i=0;i<size;++i)
    data[i]=v.data[i];
  return *this;
}
б) для случая, когда память перевыделяется
class String {
  int len;
  char * str;
public:
  String &operator=(const String &);
  ...
};
String & String::operator=(const String &s)
{ String t(s); // создание копии
  std::swap(len,t.len); // обмен состояний объекта t и *this
  std::swap(str,t.str);
  return *this; // объект t со старым состоянием *this уничтожается
}
Определение постфиксного ++ через префиксный:
class A {
  ...
public:
  A& operator++();
};
inline A operator++(A &x, int)
{ A t(x);
  ++x;
  return t;
}
Определение + через += :
class A {
  ...
public:
  A& operator+=(const A&);
};
inline A operator+(A x, const A &y) // первый параметр передается по значению
{ return x+=y;
}
Определение != > >= <= через == и < в C++17:
#include <utility>
using namespace std::rel_ops;
class A {
  ...
public:
  friend bool operator==(const A&, const A&);
  friend bool operator<(const A&, const A&);
};
В явном виде эти операции нужно определять всегда так:
inline bool operator!=(const A &x, const A &y)
{ return !(x==y);
}
inline bool operator>(const A &x, const A &y)
{ return y<x;
}
inline bool operator>=(const A &x, const A &y)
{ return !(x<y);
}
inline bool operator<=(const A &x, const A &y)
{ return !(y<x);
}
Использование нового оператора в C++20:
#include <compare>
class A {
...
friend auto operator<=>(const A&, const A&) = default;
};
По умолчанию сравнение полей выполняется в порядке перечисления в классе. В случае явного определения нужно вернуть значение типа strong_ordering (одинаковые значения неразличимы), weak_ordering (одинаковые значения различимы, например, сравнение без учета регистра) или partial_ordering (сравнение возможно не всегда, например, с NaN для вещественных чисел), в которых определены константы less, great, equal (для strong_ordering), equivalent (для weak_ordering и partial_ordering, unordered (для partial_ordering).

Перегрузка операции индексирования:
class BadIndex {}; // класс для информирования об ошибке
class Vector {
  const int size;
  double *const data;
public:
  double &operator[](int); // для неконстантных объектов
  double operator[](int) const; // для константных объектов
  ...
};
double & Vector::operator[](int i)
{ if(i<0 || i>=size)
    throw BadIndex();
  return data[i];
}
double Vector::operator[](int i) const
{ if(i<0 || i>=size)
    throw BadIndex();
  return data[i];
}
int main()
{ Vector a(10); // вектор из 10 элементов
  a[4]=a[5]*2; // изменяем элемент вектора
}
В C++23 можно перегружать операцию [] для индексации по двум или более ключам:
class Matrix {
public:
  Matrix(int n, int m);
  double &operator[](int i, int j);
  double operator[](int i, int j) const;
};
int main()
{ Matrix a(10,10); // матрица 10x10
  a[4,5]=1; // изменяем элемент матрицы
}
Перегрузка &, -> и *:
class A;
class Ptr { // умный указатель
public:
  A *operator->();
  A &operator*();
  ...
};
class A {
public:
  Ptr operator&(); // создание умного указателя
  ...
};
Перегрузка операции () для создания функционалов:
struct str_less { // функционал для сравнения двух строк
  bool operator()(const char *a, const char *b)
  { return strcmp(a,b)<0;
  }
};
int main()
{ char *s[100];
  sort(s,s+100,str_less()); // использование функционала
}
Перегрузка операций << и >> ввода-вывода:
class Point {
  double x,y;
public:
  friend istream &operator>>(istream &, Point&);
  friend ostream &operator<<(ostream &, const Point&);
};
istream &operator>>(istream &s, Point &p)
{ char c;
  return s>>c>>p.x>>c>>p.y>>c; // вводим разделительные символы, не проверяя
}
ostream &operator<<(ostream &s, const Point &p);
{ return s<<"("<<p.x<<","<<p.y<<")"; // \n не выводится!
}
Формат ввода должен точно соответствовать формату вывода, не должно быть подсказок на ввод.

Чтобы проверить формат ввода
istream &operator>>(istream &s, Point &p)
{ char c;
  if(!(s>>ws && // пропустить пробелы
       s.peek()=='(' && s>>c>>p.x>>ws && s.peek()==',' &&
       s>>c>>p.y>>ws && s.peek()==')' && s>>c))
     s.clear(ios_base::failbit); 
  return s;
}
// Обработка ошибок для ввода с консоли
  while(!(cin>>p)) {
     // сообщить об ошибке формата ввода
     cin.clear(); // сбросить флаг ошибки
     cin.ignore(256,'\n'); // пропустить до Enter
     // попросить ввести повторно, указав формат
  }
// Обработка ошибок для ввода из файла
  cin.exceptions(ios_base::failbit);
  cin>>p;
loading