35 }
36 #endif
Операторы можно реализовать либо как функции—члены, либо как глобальные функции. В нашем примере мы реализовали операторы += и —= как функции—члены, а операторы + и — как глобальные функции.
Операторы += и —= принимают ссылку на другой объект Point2D и увеличивают или уменьшают координаты x и у текущего объекта на значение координат другого объекта. Они возвращают *this, т.е. ссылку на текущий объект (this имеет тип Point2D *). Возвращение ссылки позволяет создавать экзотический программный код, например:
a += b += с;
Операторы + и — принимают два параметра и возвращают значение объекта Point2D (а не ссылку на существующий объект). Ключевое слово inline позволяет поместить эти функции в заголовочный файл. Если бы тело функции было более длинным, мы бы поместили в заголовочный файл прототип функции, а определение функции (без ключевого слова inline) в файл .cpp.
Следующие фрагменты программного кода показывают, как можно использовать все четыре перегруженных оператора:
Point2D beta(77.5, 50.0);
Point2D alpha(12.5, 40.0);
alpha += beta;
beta -= alpha;
Point2D gamma = alpha + beta;
Point2D delta = beta - alpha;
Кроме того, можно вызывать функции operator точно так же, как вызываются любые другие функции:
Point2D beta(77.5, 50.0);
Point2D alpha(12.5, 40.0);
alpha.operator+=(beta);
beta.operator-=(alpha);
Point2D gamma = operator+(alpha, beta);
Point2D delta = operator-(beta, alpha);
Перегрузка операторов в С++ представляет собой сложную тему, однако мы вполне можем пока обходиться без знания всех деталей. Все же важно понимать принципы перегрузки операторов, потому что несколько классов Qt (в том числе QString и QVector<T>) используют их для обеспечения простого и более естественного синтаксиса для таких операций, как конкатенация и добавление в конец объекта.
Типы значений
B Java и C# различаются типы значений и типы ссылок.
• Типы значений. Это такие элементарные типы, как char, int и float, а также структуры struct в C#. Характерным для них является то, что для их создания не используется оператор new и оператор присваивания копирует значение переменной. Например:
int i = 5;
int j = 10;
i = j;
• Типы ссылок. Это такие классы, как Integer (в Java), String и MyVeryOwnClass. Их экземпляры создаются при помощи оператора new. Оператор присваивания копирует только ссылку на объект, а для действительного копирования объекта мы должны вызывать функцию clone() (в Java) или Clone() (в C#). Например:
Integer i = new Integer(5);
Integer j = new Integer(10);
i = j.clone();
В С++ все типы могут использоваться как «типы ссылок», а в дополнение к этому те из них, которые допускают копирование, могут использоваться как «типы значений». Например, в С++ нет необходимости иметь класс, подобный Integer, потому что можно использовать указатели и оператор new:
int *i = new int(5);
int *j = new int(10);
*i = *j;
В отличие от Java и C#, в С++ определяемые пользователем типы используются так же, как встроенные типы:
Point2D *i = new Point2D(5, 5);
Point2D *j = new Point2D(10, 10);
*i = *j;
Если требуется сделать класс С++ копируемым, необходимо предусмотреть в этом классе конструктор копирования и оператор присваивания. Конструктор копирования вызывается при инициализации объекта другим объектом того же типа. Синтаксически в С++ это обеспечивается двумя способами:
Point2D i(20, 20);
Point2D j(i); // первый способ
Point2D k = i; // второй способ
Оператор присваивания вызывается при присваивании одной переменной другой переменной:
Point2D i(5, 5);
Point2D j(10, 10);
j = i;
При определении класса компилятор С++ автоматически обеспечивает конструктор копирования и оператор присваивания, выполняющие копирование члена в член. Для класса Point2D это равносильно тому, как если бы мы написали следующий программный код в определении класса:
01 class Point2D
02 {
03 public:
04 Point2D(const Point2D &other)
05 : xVal(other.xVal), yVal(other.yVal) { }
06 Point2D &operator=(const Point2D &other)