if (obj.isbn() == Primer_5th_ed.isbn()) // ошибка: obj - функция

Проблема в том, что, несмотря на намерение объявить инициализированный значением по умолчанию объект obj, фактически была объявлена функция без параметров, возвращающая объект типа Sales_data.

Чтобы правильно определить объект, использующий стандартный конструктор для инициализации, следует убрать пустые круглые скобки:

// ok: obj - объект, инициализированный значением по умолчанию

Sales_data obj;

Распространенной ошибкой среди новичков в С++ является объявление объекта, инициализированного стандартным конструктором, следующим образом:

Sales_data obj(); // упс! Это объявление функции, а не создание объекта

Sales_data obj2;  // ok: obj2 - это объект, а не функция

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

Упражнение 7.43. Предположим, имеется класс NoDefault, у которого есть конструктор, получающий параметр типа int, но нет стандартного конструктора. Определите класс С, у которого есть переменная-член типа NoDefault. Определите стандартный конструктор для класса С.

Упражнение 7.44. Допустимо ли следующее объявление? Если нет, то почему?

vector vec(10);

Упражнение 7.45. Определите вектор, содержащий объекты типа С из предыдущего упражнения?

Упражнение 7.46. Которое из следующих утверждений, если таковое имеется, ложно? Почему?

(a) Класс должен предоставить по крайней мере один конструктор.

(b) Стандартный конструктор — это конструктор с пустым списком параметров.

(c) Если для класса не нужно никаких значений по умолчанию, то класс не должен предоставлять стандартный конструктор.

(d) Если класс не определяет стандартный конструктор, компилятор сам создает конструктор, который инициализирует каждую переменную-член значением по умолчанию соответствующего типа.

<p><image l:href="#reader.png"/>7.5.4. Неявное преобразование типов класса</p>

Как упоминалось в разделе 4.11, язык С++ автоматически осуществляет преобразование некоторых встроенных типов. Обращалось также внимание на то, что классы тоже могут определять неявные преобразования. Каждый конструктор, который может быть вызван с одним аргументом, определяет неявное преобразование в тип класса. Такие конструкторы иногда упоминают как конструкторы преобразования (converting constructor). Определение преобразования из типа класса в другой тип рассматривается в разделе 14.9.

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

Конструкторы класса Sales_data, получающие строку и объект класса istream, оба определяют неявные преобразования из этих типов в тип Sales_data. Таким образом, можно использовать тип string или istream там, где ожидается объект типа Sales_data:

string null_book = "9-999-99999-9";

// создает временный объект типа Sales_data

// с units_sold и revenue равными 0 и bookNo равным null_book

item.combine(null_book);

Здесь происходит вызов функции-члена combine() класса Sales_data со строковым аргументом. Этот вызов совершенно корректен; компилятор автоматически создаст объект класса Sales_data из данной строки. Этот вновь созданный (временный) объект класса Sales_data передается функции combine(). Поскольку параметр функции combine() является ссылкой на константу, этому параметру можно передать временный объект.

Допустимо только одно преобразование типов класса

В разделе 4.11.2 обращалось внимание на то, что компилятор автоматически применит только одно преобразование типов класса. Например, следующий код ошибочен, поскольку он неявно использует два преобразования:

// ошибка: требует двух пользовательских преобразований:

//   (1) преобразование "9-999-99999-9" в string

//   (2) преобразование временной строки в Sales_data

item.combine("9-999-99999-9");

Если данный вызов необходим, это можно сделать при явном преобразовании символьной строки в объект класса string или в объект класса Sales_data:

// ok: явное преобразование в string,

// неявное преобразование в Sales_data

item.combine(string("9-999-99999-9"));

// ok: неявное преобразование в string,

Перейти на страницу:

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