- Любовные романы
- Фантастика и фэнтези
- Ироническое фэнтези
- Научная Фантастика
- Фэнтези
- Ужасы и Мистика
- Боевая фантастика
- Альтернативная история
- Космическая фантастика
- Попаданцы
- Юмористическая фантастика
- Героическая фантастика
- Детективная фантастика
- Социально-психологическая
- Боевое фэнтези
- Русское фэнтези
- Киберпанк
- Романтическая фантастика
- Городская фантастика
- Технофэнтези
- Мистика
- Разная фантастика
- Иностранное фэнтези
- Историческое фэнтези
- LitRPG
- Эпическая фантастика
- Зарубежная фантастика
- Городское фентези
- Космоопера
- Разное фэнтези
- Книги магов
- Любовное фэнтези
- Постапокалипсис
- Бизнес
- Историческая фантастика
- Социально-философская фантастика
- Сказочная фантастика
- Стимпанк
- Романтическое фэнтези
- Ироническая фантастика
- Детективы и Триллеры
- Проза
- Феерия
- Новелла
- Русская классическая проза
- Современная проза
- Повести
- Контркультура
- Русская современная проза
- Историческая проза
- Проза
- Классическая проза
- Советская классическая проза
- О войне
- Зарубежная современная проза
- Рассказы
- Зарубежная классика
- Очерки
- Антисоветская литература
- Магический реализм
- Разное
- Сентиментальная проза
- Афоризмы
- Эссе
- Эпистолярная проза
- Семейный роман/Семейная сага
- Поэзия, Драматургия
- Приключения
- Детская литература
- Загадки
- Книга-игра
- Детская проза
- Детские приключения
- Сказка
- Прочая детская литература
- Детская фантастика
- Детские стихи
- Детская образовательная литература
- Детские остросюжетные
- Учебная литература
- Зарубежные детские книги
- Детский фольклор
- Буквари
- Книги для подростков
- Школьные учебники
- Внеклассное чтение
- Книги для дошкольников
- Детская познавательная и развивающая литература
- Детские детективы
- Домоводство, Дом и семья
- Юмор
- Документальные книги
- Бизнес
- Тайм-менеджмент
- Кадровый менеджмент
- Экономика
- Менеджмент и кадры
- Управление, подбор персонала
- О бизнесе популярно
- Интернет-бизнес
- Личные финансы
- Делопроизводство, офис
- Маркетинг, PR, реклама
- Поиск работы
- Бизнес
- Банковское дело
- Малый бизнес
- Ценные бумаги и инвестиции
- Краткое содержание
- Бухучет и аудит
- Ораторское искусство / риторика
- Корпоративная культура, бизнес
- Финансы
- Государственное и муниципальное управление
- Менеджмент
- Зарубежная деловая литература
- Продажи
- Переговоры
- Личная эффективность
- Торговля
- Научные и научно-популярные книги
- Биофизика
- География
- Экология
- Биохимия
- Рефераты
- Культурология
- Техническая литература
- История
- Психология
- Медицина
- Прочая научная литература
- Юриспруденция
- Биология
- Политика
- Литературоведение
- Религиоведение
- Научпоп
- Психология, личное
- Математика
- Психотерапия
- Социология
- Воспитание детей, педагогика
- Языкознание
- Беременность, ожидание детей
- Транспорт, военная техника
- Детская психология
- Науки: разное
- Педагогика
- Зарубежная психология
- Иностранные языки
- Филология
- Радиотехника
- Деловая литература
- Физика
- Альтернативная медицина
- Химия
- Государство и право
- Обществознание
- Образовательная литература
- Учебники
- Зоология
- Архитектура
- Науки о космосе
- Ботаника
- Астрология
- Ветеринария
- История Европы
- География
- Зарубежная публицистика
- О животных
- Шпаргалки
- Разная литература
- Боевые искусства
- Прочее
- Периодические издания
- Фанфик
- Военное
- Цитаты из афоризмов
- Гиды, путеводители
- Литература 19 века
- Зарубежная образовательная литература
- Военная история
- Кино
- Современная литература
- Военная техника, оружие
- Культура и искусство
- Музыка, музыканты
- Газеты и журналы
- Современная зарубежная литература
- Визуальные искусства
- Отраслевые издания
- Шахматы
- Недвижимость
- Великолепные истории
- Музыка, танцы
- Авто и ПДД
- Изобразительное искусство, фотография
- Истории из жизни
- Готические новеллы
- Начинающие авторы
- Спецслужбы
- Подростковая литература
- Зарубежная прикладная литература
- Религия и духовность
- Старинная литература
- Справочная литература
- Компьютеры и Интернет
- Блог
Язык программирования C++. Пятое издание - Стенли Липпман
Шрифт:
Интервал:
Закладка:
Конструкторы класса 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,
// явное преобразование в Sales_data
item.combine(Sales_data("9-999-99999-9"));
Преобразования типов класса не всегда полезныЖелательно ли преобразование типа string в Sales_data, зависит от конкретных обстоятельств. В данном случае это хорошая идея. Строка в переменной null_book, вероятнее всего, соответствует несуществующему ISBN.
Преобразование из istream в Sales_data более проблематично:
// использует конструктор istream при создании объекта для передачи
// функции combine
item.combine(cin);
Этот код неявно преобразует объект cin в объект класса Sales_item. Это преобразование осуществляет тот конструктор класса Sales_data, который получает тип istream. Этот конструктор создает (временный) объект класса Sales_data при чтении со стандартного устройства ввода. Затем этот объект передается функции same_isbn().
Этот объект класса Sales_item временный (см. раздел 2.4.1). По завершении функции combine() никакого доступа к нему не будет. Фактически создается объект, удаляющийся после того, как его значение добавляется в объект item.
Предотвращение неявных преобразований, осуществляемых конструкторомЧтобы предотвратить использование конструктора в контексте, который требует неявного преобразования, достаточно объявить его явным (explicit constructor) с использованием ключевого слова explicit:
class Sales_data {
public:
Sales_data() = default;
Sales_data(const std::string &s, unsigned n, double p):
bookNo(s), units_sold(n), revenue (p*n) { }
explicit Sales_data(const std::string &s): bookNo(s) { }
explicit Sales_data(std::istream&); // остальные члены, как прежде
};
Теперь ни один из конструкторов не применим для неявного создания объектов класса Sales_data. Ни один из предыдущих способов применения теперь не сработает:
item.combine(null_book); // ошибка: конструктор string теперь явный
item.combine(cin); // ошибка: конструктор istream теперь явный
Ключевое слово explicit имеет значение только для тех конструкторов, которые могут быть вызваны с одним аргументом. Конструкторы, требующие большего количества аргументов, не используются для неявного преобразования, поэтому нет никакой необходимости определять их как explicit. Ключевое слово explicit используется только в объявлениях конструкторов в классе. В определении вне тела класса его не повторяют.
// ошибка: ключевое слово explicit допустимо только для
// объявлений конструкторов в заголовке класса
explicit Sales_data::Sales_data(istream& is) {
read(is, *this);
}
Явные конструкторы применяются только для прямой инициализацииОдним из контекстов, в котором происходит неявное преобразования, является использование формы инициализации копированием (со знаком =) (см. раздел 3.2.1). С этой формой инициализации нельзя использовать явный конструктор; придется использовать прямую инициализацию:
Sales_data item1(null_book); // ok: прямая инициализация
// ошибка: с явным конструктором нельзя использовать форму
// инициализации копированием
Sales_data item2 = null_book;
Явный конструктор применим только с прямой формой инициализации (см. раздел 3.2.1). Кроме того, компилятор не будет использовать этот конструктор в автоматическом преобразовании.
Применение явных конструкторов для преобразованийХотя компилятор не будет использовать явный конструктор для неявного преобразования, его можно использовать для преобразования явно:
// ok: аргумент - явно созданный объект класса Sales_data
item.combine(Sales_data(null_book));
// ok: static_cast может использовать явный конструктор
item.combine(static_cast<Sales_data>(cin));
В первом вызове конструктор Sales_data() используется непосредственно. Этот вызов создает временный объект класса Sales_data, используя конструктор Sales_data(), получающий строку. Во втором вызове используется оператор static_cast (см. раздел 4.11.3) для выполнения явного, а не неявного преобразования. В этом вызове оператор static_cast использует для создания временного объекта класса Sales_data конструктор с параметром типа istream.
Библиотечные классы с явными конструкторамиУ некоторых библиотечных классов, включая уже использованные ранее, есть конструкторы с одним параметром.
• Конструктор класса string, получающий один параметр типа const char* (см. раздел 3.2.1), не является явным.
• Конструктор класса vector, получающий размер вектора (см. раздел 3.3.1), является явным.
Упражнения раздела 7.5.4Упражнение 7.47. Объясните, должен ли быть явным конструктор Sales_data(), получающий строку. Каковы преимущества объявления конструктора явным? Каковы недостатки?
Упражнение 7.48. С учетом того, что конструктор Sales_data() не является явным, какие операции происходят во время следующих определений:
string null_isbn("9-999-99999-9");
Sales_data item1(null_isbn);
Sales_data item2("9-999-99999-9");
Что будет при явном конструкторе Sales_data()?
Упражнение 7.49. Объясните по каждому из следующих трех объявлений функции combine(), что происходит при вызове i.combine(s), где i — это объект класса Sales_data, a s — строка:
(a) Sales_data &combine(Sales_data);
(b) Sales_data &combine(Sales_data&);
(c) Sales_data &combine(const Sales_data&) const;
Упражнение 7.50. Определите, должен ли какой-либо из конструкторов вашего класса Person быть явным.
Упражнение 7.51. Как, по вашему, почему вектор определяет свой конструктор с одним аргументом как явный, а строка нет?
7.5.5. Агрегатные классы
Агрегатный класс (aggregate class) предоставляет пользователям прямой доступ к своим членам и имеет специальный синтаксис инициализации. Класс считается агрегатным в следующем случае.
• Все его переменные-члены являются открытыми (public).
• Он не определяет конструкторы.
• У него нет никаких внутриклассовых инициализаторов (см. раздел 2.6.1).
• У него нет никаких базовых классов или виртуальных функций, связанных с классом средствами, которые рассматриваются в главе 15.
Например, следующий класс является агрегатным:
struct Data {
int ival;
string s;
};
Для инициализации переменных-членов агрегатного класса можно предоставить заключенный в фигурные скобки список инициализаторов для переменных-членов:
// val1.ival = 0; val1.s = string("Anna")
