- Любовные романы
- Фантастика и фэнтези
- Ненаучная фантастика
- Ироническое фэнтези
- Научная Фантастика
- Фэнтези
- Ужасы и Мистика
- Боевая фантастика
- Альтернативная история
- Космическая фантастика
- Попаданцы
- Юмористическая фантастика
- Героическая фантастика
- Детективная фантастика
- Социально-психологическая
- Боевое фэнтези
- Русское фэнтези
- Киберпанк
- Романтическая фантастика
- Городская фантастика
- Технофэнтези
- Мистика
- Разная фантастика
- Иностранное фэнтези
- Историческое фэнтези
- LitRPG
- Эпическая фантастика
- Зарубежная фантастика
- Городское фентези
- Космоопера
- Разное фэнтези
- Книги магов
- Любовное фэнтези
- Постапокалипсис
- Бизнес
- Историческая фантастика
- Социально-философская фантастика
- Сказочная фантастика
- Стимпанк
- Романтическое фэнтези
- Ироническая фантастика
- Детективы и Триллеры
- Проза
- Юмор
- Феерия
- Новелла
- Русская классическая проза
- Современная проза
- Повести
- Контркультура
- Русская современная проза
- Историческая проза
- Проза
- Классическая проза
- Советская классическая проза
- О войне
- Зарубежная современная проза
- Рассказы
- Зарубежная классика
- Очерки
- Антисоветская литература
- Магический реализм
- Разное
- Сентиментальная проза
- Афоризмы
- Эссе
- Эпистолярная проза
- Семейный роман/Семейная сага
- Поэзия, Драматургия
- Приключения
- Детская литература
- Загадки
- Книга-игра
- Детская проза
- Детские приключения
- Сказка
- Прочая детская литература
- Детская фантастика
- Детские стихи
- Детская образовательная литература
- Детские остросюжетные
- Учебная литература
- Зарубежные детские книги
- Детский фольклор
- Буквари
- Книги для подростков
- Школьные учебники
- Внеклассное чтение
- Книги для дошкольников
- Детская познавательная и развивающая литература
- Детские детективы
- Домоводство, Дом и семья
- Юмор
- Документальные книги
- Бизнес
- Работа с клиентами
- Тайм-менеджмент
- Кадровый менеджмент
- Экономика
- Менеджмент и кадры
- Управление, подбор персонала
- О бизнесе популярно
- Интернет-бизнес
- Личные финансы
- Делопроизводство, офис
- Маркетинг, PR, реклама
- Поиск работы
- Бизнес
- Банковское дело
- Малый бизнес
- Ценные бумаги и инвестиции
- Краткое содержание
- Бухучет и аудит
- Ораторское искусство / риторика
- Корпоративная культура, бизнес
- Финансы
- Государственное и муниципальное управление
- Менеджмент
- Зарубежная деловая литература
- Продажи
- Переговоры
- Личная эффективность
- Торговля
- Научные и научно-популярные книги
- Биофизика
- География
- Экология
- Биохимия
- Рефераты
- Культурология
- Техническая литература
- История
- Психология
- Медицина
- Прочая научная литература
- Юриспруденция
- Биология
- Политика
- Литературоведение
- Религиоведение
- Научпоп
- Психология, личное
- Математика
- Психотерапия
- Социология
- Воспитание детей, педагогика
- Языкознание
- Беременность, ожидание детей
- Транспорт, военная техника
- Детская психология
- Науки: разное
- Педагогика
- Зарубежная психология
- Иностранные языки
- Филология
- Радиотехника
- Деловая литература
- Физика
- Альтернативная медицина
- Химия
- Государство и право
- Обществознание
- Образовательная литература
- Учебники
- Зоология
- Архитектура
- Науки о космосе
- Ботаника
- Астрология
- Ветеринария
- История Европы
- География
- Зарубежная публицистика
- О животных
- Шпаргалки
- Разная литература
- Зарубежная литература о культуре и искусстве
- Пословицы, поговорки
- Боевые искусства
- Прочее
- Периодические издания
- Фанфик
- Военное
- Цитаты из афоризмов
- Гиды, путеводители
- Литература 19 века
- Зарубежная образовательная литература
- Военная история
- Кино
- Современная литература
- Военная техника, оружие
- Культура и искусство
- Музыка, музыканты
- Газеты и журналы
- Современная зарубежная литература
- Визуальные искусства
- Отраслевые издания
- Шахматы
- Недвижимость
- Великолепные истории
- Музыка, танцы
- Авто и ПДД
- Изобразительное искусство, фотография
- Истории из жизни
- Готические новеллы
- Начинающие авторы
- Спецслужбы
- Подростковая литература
- Зарубежная прикладная литература
- Религия и духовность
- Старинная литература
- Справочная литература
- Компьютеры и Интернет
- Блог
Язык программирования C++. Пятое издание - Стенли Липпман
Шрифт:
Интервал:
Закладка:
Record lookup(Phone);
Record lookup(const Phone); // повторно объявляет Record lookup(Phone)
Record lookup(Phone*);
Record lookup(Phone* const); // повторно объявляет
// Record lookup(Phone*)
Здесь вторые объявления повторно объявляет ту же функцию, что и первые. С другой стороны, функцию можно перегрузить на основании того, является ли параметр ссылкой (или указателем) на константную или неконстантную версию того же типа; речь идет о спецификаторе const нижнего уровня:
// функции, получающие константную и неконстантную ссылку (или
// указатель), имеют разные параметры
Record lookup(Account&); // функция получает ссылку на Account
Record lookup(const Account&); // новая функция получает константную
// ссылку
Record lookup(Account*); // новая функция получает указатель
// на Account
Record lookup(const Account*); // новая функция получает указатель на
// константу
В этих случаях компилятор может использовать константность аргумента, чтобы различить, какую функцию применять. Поскольку нет преобразования (см. раздел 4.11.2) из константы, можно передать константный объект (или указатель на константу) только версии с константным параметром. Так как преобразование в константу возможно, можно вызвать функцию и неконстантного объекта, и указателя на неконстантный объект. Однако, как будет представлено в разделе 6.6.1, компилятор предпочтет неконстантные версии при передаче неконстантного объекта или указателя на неконстантный объект.
Совет. Когда не следует перегружать функцииХотя перегрузка функций позволяет избежать необходимости создавать и запоминать имена общепринятых операций, она не всегда целесообразна. В некоторых случаях разные имена функций предоставляют дополнительную информацию, которая упрощает понимание программы. Давайте рассмотрим набор функций-членов класса Screen, отвечающих за перемещение курсора.
Screen& moveHome();
Screen& moveAbs(int, int);
Screen& moveRel(int, int, string direction);
На первый взгляд может показаться, что этот набор функций имеет смысл перегрузить под именем move:
Screen& move();
Screen& move(int, int);
Screen& move(int, int, string direction);
Однако при перегрузке этих функций мы потеряли информацию, которая была унаследована именами функции. Хотя перемещение курсора — это общая операция, совместно используемая всеми этими функциями, специфический характер перемещения уникален для каждой из этих функций. Рассмотрим, например, функцию moveHome(), осуществляющую вполне определенное перемещение курсора. Какое из двух приведенных ниже обращений понятнее при чтении кода?
// которая из записей понятней?
myScreen.moveHome(); // вероятно, эта!
myScreen.move();
Оператор const_cast и перегрузкаВ разделе 4.11.3 упоминалось, что оператор const_cast особенно полезен в контексте перегруженных функций. В качестве примера вернемся к функции shorterString() из раздела 6.3.2:
// возвратить ссылку на строку, которая короче
const string &shorterString (const string &s1, const string &s2) {
return s1.size() <= s2.size() ? s1 : s2;
}
Эта функция получает и возвращает ссылки на константную строку. Мы можем вызвать функцию с двумя неконстантными строковыми аргументами, но как результат получим ссылку на константную строку. Могла бы понадобиться версия функции shorterString(), которая, получив неконстантные аргументы, возвратит обычную ссылку. Мы можем написать эту версию функции, используя оператор const_cast:
string &shorterString(string &s1, string &s2) {
auto &r = shorterString(const_cast<const string&>(s1),
const_cast<const string&>(s2));
return const_cast<string&>(r);
}
Эта версия вызывает константную версию функции shorterString() при приведении типов ее аргументов к ссылкам на константу. Функция возвращает ссылку на тип const string, которая, как известно, привязана к одному из исходных, неконстантных аргументов. Следовательно, приведение этой строки назад к обычной ссылке string& при возвращении вполне безопасно.
Вызов перегруженной функцииКогда набор перегруженных функций определен, необходима возможность вызвать их с соответствующими аргументами. Подбор функции (function matching), известный также как поиск перегруженной функции (overload resolution), — это процесс, в ходе которого вызов функции ассоциируется с определенной версией из набора перегруженных функций. Компилятор определяет, какую именно версию функции использовать при вызове, сравнивая аргументы вызова с параметрами каждой функции в наборе.
Как правило, вовсе несложно выяснить, допустим ли вызов, и если он допустим, то какая из версий функции будет использована компилятором. Функции в наборе перегруженных версий отличаются количеством или типом аргументов. В таких случаях определить используемую функцию просто. Подбор функции усложняется в случае, когда количество параметров одинаково и они допускают преобразование (см. раздел 4.11) переданных аргументов. Распознавание вызовов компилятором при наличии преобразований рассматривается в разделе 6.6, а пока следует понять, что при любом вызове перегруженной функции возможен один из трех результатов.
• Компилятор находит одну функцию, которая является наилучшим соответствием (best match) для фактических аргументов, и создает код ее вызова.
• Компилятор не может найти ни одной функции, параметры которой соответствуют аргументам вызова. В этом случае компилятор сообщает об ошибке отсутствия соответствия (no match).
• Компилятор находит несколько функций, которые в принципе подходят, но ни одна из них не соответствует полностью. В этом случае компилятор также сообщает об ошибке, об ошибке неоднозначности вызова (ambiguous call).
Упражнения раздела 6.4Упражнение 6.39. Объясните результат второго объявления в каждом из следующих наборов. Укажите, какое из них (если есть) недопустимо.
(a) int calc(int, int);
int calc(const int, const int);
(b) int get();
double get();
(c) int *reset(int *);
double *reset(double *);
6.4.1. Перегрузка и область видимости
Обычно объявлять функцию локально нежелательно. Но чтобы объяснить, как область видимости взаимодействует с перегрузкой, мы будем нарушать это правило и используем локальные объявление функции.
Новички в программировании на языке С++ зачастую не понимают взаимодействия между областью видимости и перегрузкой. Однако у перегрузки нет никаких специальных свойств относительно области видимости. Как обычно, если имя объявлено во внутренней области видимости, оно скрывает (hidden name) такое же имя, объявленное во внешней области видимости. Имена не перегружают в областях видимости:
string read();
void print(const string &);
void print(double); // перегружает функцию print
void fooBar(int ival) {
bool read = false; // новая область видимости: скрывает
// предыдущее объявление имени read
string s = read(); // ошибка: read - переменная типа bool, а не
// функция
// плохой подход: обычно не следует объявлять функции в локальной
// области видимости
void print(int); // новая область видимости: скрывает предыдущие
// экземпляры функции print
print("Value: "); // ошибка: print(const string &) скрыта
print(ival); // ok: print (int) видима
print(3.14); // ok: вызов print(int); print(double) скрыта
}
Большинство читателей не удивит ошибка при вызове функции read(). Когда компилятор обрабатывает вызов функции read(), он находит локальное определение имени read. Это имя принадлежит переменной типа bool, а не функции. Следовательно, вызов некорректен.
Точно тот же процесс используется при распознавании вызова функции print(). Объявление print(int) в функции fooBar скрывает прежнее ее объявление. В результате будет доступна только одна функция print(), та, которая получает один параметр типа int.

