string s = "world";

string t = s + "!";  // ok: const char* можно добавить к строке

string u = "hi" + s; // возможна ошибка, если + будет членом

                     // класса string

Если бы оператор operator+ был членом класса string, то первый случай сложения был бы эквивалентен s.operator+("!"). Аналогично сложение "hi" + s было бы эквивалентно "hi".operator+(s). Однако литерал "hi" имеет тип const char*, т.е. встроенный тип; у него нет функций-членов.

Поскольку класс string определяет оператор + как обычную функцию, не являющуюся членом класса, сложение "hi" + s эквивалентно вызову operator+("hi", s). Подобно любому вызову функции, каждый из аргументов должен быть преобразуем в тип параметра. Единственное требование — по крайней мере один из операндов должен иметь тип класса, а оба операнда могут быть преобразованы в строку.

Упражнения раздела 14.1

Упражнение 14.1. Чем перегруженный оператор отличается от встроенного? В чем перегруженные операторы совпадают со встроенными?

Упражнение 14.2. Напишите объявления для перегруженных операторов ввода, вывода, сложения и составного присвоения для класса Sales_data.

Упражнение 14.3. Классы string и vector определяют перегруженный оператор ==, применимый для сравнения объектов этих типов. Если векторы svec1 и svec2 содержат строки, объясните, какая из версий оператора == применяется в каждом из следующих выражений:

(a) "cobble" == "stone" (b) svec1[0] == svec2[0]

(c) svec1 == svec2      (d) "svec1[0] == "stone"

Упражнение 14.4. Объясните, должен ли каждый из следующих операторов быть членом класса и почему?

(а) % (b) %= (с) ++ (d) -> (е) << (f) && (g) == (h) ()

Упражнение 14.5. В упражнении 7.40 из раздела 7.5.1 был приведен набросок одного из следующих классов. Какой из перегруженных операторов должен (если должен) предоставить класс.

(a) Book    (b) Date   (с) Employee

(d) Vehicle (e) Object (f) Tree

<p><image l:href="#reader.png"/>14.2. Операторы ввода и вывода</p>

Как уже упоминалось, библиотека IO использует операторы >> и << для ввода и вывода соответственно. Сама библиотека IO определяет версии этих операторов для ввода и вывода данных встроенных типов. Классы, нуждающиеся во вводе и выводе, обычно определяют версии этих операторов для объектов данного класса.

<p><image l:href="#reader.png"/>14.2.1. Перегрузка оператора вывода <code><<</code></p>

Обычно первый параметр оператора вывода является ссылкой на неконстантный объект класса ostream. Объект класса ostream неконстантен потому, что запись в поток изменяет его состояние. Параметр является ссылкой потому, что нельзя копировать объект класса ostream.

Второй параметр обычно должен быть ссылкой на константу типа класса, объект которого необходимо вывести. Параметр должен быть ссылкой во избежание копирования аргумента. Но он может быть константной ссылкой потому, что вывод объекта обычно не изменяет его.

Для совместимости с другими операторами вывода оператор operator<< обычно возвращает свой параметр типа ostream.

Оператор вывода класса Sales_data

Для примера напишем оператор вывода для класса Sales_data:

ostream &operator<<(ostream &os, const Sales_data &item) {

 os << item.isbn() << " " << item.units_sold << " "

    << item.revenue << " " << item.avg_price();

 return os;

}

За исключением имени эта функция идентична прежней версии функции print() (см. раздел 7.1.3). Вывод объекта класса Sales_data требует вывода значений всех его трех переменных-членов, а также вычисления средней цены (average price). Каждый элемент отделяется пробелом. После вывода значений оператор возвращает ссылку на использованный для этого объект класса ostream.

Операторы вывода обеспечивают минимум форматирования

Операторы вывода встроенных типов форматирования практически не обеспечивают. В частности, они не выводят символ новой строки. Пользователи ожидают, что операторы вывода класса будут вести себя так же. Если бы оператор выводил новую строку, то пользователь не смог бы вывести содержимое объекта с описывающим его текстом в одной строке. Оператор вывода, обеспечивающий минимум форматирования, позволяет контролировать подробности вывода пользователям.

Обычно операторы вывода должны выводить содержимое объекта с минимальным форматированием. Они не должны выводить новую строку. 

Операторы ввода-вывода не должны быть функциями-членами класса
Перейти на страницу:

Похожие книги