- •Часть I
 - •1. Начинаем
 - •1.1. Решение задачи
 - •1.2.1. Порядок выполнения инструкций
 - •1.3. Директивы препроцессора
 - •1.4. Немного о комментариях
 - •1.5. Первый взгляд на ввод/вывод
 - •1.5.1. Файловый ввод/вывод
 - •2.1. Встроенный тип данных “массив”
 - •2.2. Динамическое выделение памяти и указатели
 - •2.3. Объектный подход
 - •2.4. Объектно-ориентированный подход
 - •2.5. Использование шаблонов
 - •2.6. Использование исключений
 - •2.7. Использование пространства имен
 - •2.8. Стандартный массив – это вектор
 - •Часть II
 - •3.1. Литералы
 - •3.2. Переменные
 - •3.2.1. Что такое переменная
 - •3.2.2. Имя переменной
 - •3.2.3. Определение объекта
 - •3.3. Указатели
 - •3.4. Строковые типы
 - •3.4.1. Встроенный строковый тип
 - •3.4.2. Класс string
 - •3.5. Спецификатор const
 - •3.6. Ссылочный тип
 - •3.8. Перечисления
 - •3.9. Тип “массив”
 - •3.9.1. Многомерные массивы
 - •3.9.2. Взаимосвязь массивов и указателей
 - •3.10. Класс vector
 - •3.11. Класс complex
 - •3.12. Директива typedef
 - •3.13. Спецификатор volatile
 - •3.14. Класс pair
 - •3.15. Типы классов
 - •4. Выражения
 - •4.1. Что такое выражение?
 - •4.2. Арифметические операции
 - •4.3. Операции сравнения и логические операции
 - •4.4. Операции присваивания
 - •4.5. Операции инкремента и декремента
 - •4.6. Операции с комплексными числами
 - •4.7. Условное выражение
 - •4.8. Оператор sizeof
 - •4.9. Операторы new и delete
 - •4.10. Оператор “запятая”
 - •4.11. Побитовые операторы
 - •4.12. Класс bitset
 - •4.13. Приоритеты
 - •4.14. Преобразования типов
 - •4.14.1. Неявное преобразование типов
 - •4.14.2. Арифметические преобразования типов
 - •4.14.3. Явное преобразование типов
 - •4.14.4. Устаревшая форма явного преобразования
 - •4.15. Пример: реализация класса Stack
 - •5. Инструкции
 - •5.1. Простые и составные инструкции
 - •5.2. Инструкции объявления
 - •5.3. Инструкция if
 - •5.4. Инструкция switch
 - •5.5. Инструкция цикла for
 - •5.6. Инструкция while
 - •5.8. Инструкция do while
 - •5.8. Инструкция break
 - •5.9. Инструкция continue
 - •5.10. Инструкция goto
 - •5.11. Пример связанного списка
 - •5.11.1. Обобщенный список
 - •6. Абстрактные контейнерные типы
 - •6.1. Система текстового поиска
 - •6.2. Вектор или список?
 - •6.3. Как растет вектор?
 - •6.4. Как определить последовательный контейнер?
 - •6.5. Итераторы
 - •6.6. Операции с последовательными контейнерами
 - •6.6.1. Удаление
 - •6.6.2. Присваивание и обмен
 - •6.6.3. Обобщенные алгоритмы
 - •6.7. Читаем текстовый файл
 - •6.8. Выделяем слова в строке
 - •6.9. Обрабатываем знаки препинания
 - •6.10. Приводим слова к стандартной форме
 - •6.11. Дополнительные операции со строками
 - •6.12. Строим отображение позиций слов
 - •6.12.1. Определение объекта map и заполнение его элементами
 - •6.12.2. Поиск и извлечение элемента отображения
 - •6.12.3. Навигация по элементам отображения
 - •6.12.4. Словарь
 - •6.12.5. Удаление элементов map
 - •6.13. Построение набора стоп-слов
 - •6.13.1. Определение объекта set и заполнение его элементами
 - •6.13.2. Поиск элемента
 - •6.13.3. Навигация по множеству
 - •6.14. Окончательная программа
 - •6.15. Контейнеры multimap и multiset
 - •6.16. Стек
 - •6.17. Очередь и очередь с приоритетами
 - •6.18. Вернемся в классу iStack
 - •Часть III
 - •7. Функции
 - •7.1. Введение
 - •7.2. Прототип функции
 - •7.2.1. Тип возвращаемого функцией значения
 - •7.2.2. Список параметров функции
 - •7.2.3. Проверка типов формальных параметров
 - •7.3. Передача аргументов
 - •7.3.1. Параметры-ссылки
 - •7.3.2. Параметры-ссылки и параметры-указатели
 - •7.3.3. Параметры-массивы
 - •7.3.4. Абстрактные контейнерные типы в качестве параметров
 - •7.3.5. Значения параметров по умолчанию
 - •7.3.6. Многоточие
 - •7.4. Возврат значения
 - •7.4.1. Передача данных через параметры и через глобальные объекты
 - •7.5. Рекурсия
 - •7.6. Встроенные функции
 - •7.7. Директива связывания extern "c" a
 - •7.8. Функция main(): разбор параметров командной строки
 - •7.8.1. Класс для обработки параметров командной строки
 - •7.9. Указатели на функции
 - •7.9.1. Тип указателя на функцию
 - •7.9.2. Инициализация и присваивание
 - •7.9.3. Вызов
 - •7.9.4. Массивы указателей на функции
 - •7.9.5. Параметры и тип возврата
 - •7.9.6. Указатели на функции, объявленные как extern "c"
 - •8. Область видимости и время жизни
 - •8.1. Область видимости
 - •8.1.1. Локальная область видимости
 - •8.2. Глобальные объекты и функции
 - •8.2.1. Объявления и определения
 - •8.2.2. Сопоставление объявлений в разных файлах
 - •8.2.3. Несколько слов о заголовочных файлах
 - •8.3. Локальные объекты
 - •8.3.1. Автоматические объекты
 - •8.3.2. Регистровые автоматические объекты
 - •8.3.3. Статические локальные объекты
 - •8.4. Динамически размещаемые объекты
 - •8.4.1. Динамическое создание и уничтожение единичных объектов
 - •8.4.2. Шаблон auto_ptr а
 - •8.4.3. Динамическое создание и уничтожение массивов
 - •8.4.4. Динамическое создание и уничтожение константных объектов
 - •8.4.5. Оператор размещения new а
 - •8.5. Определения пространства имен а
 - •8.5.1. Определения пространства имен
 - •8.5.2. Оператор разрешения области видимости
 - •8.5.3. Вложенные пространства имен
 - •8.5.4. Определение члена пространства имен
 - •8.5.5. Поо и члены пространства имен
 - •8.5.6. Безымянные пространства имен
 - •8.6. Использование членов пространства имен а
 - •8.6.1. Псевдонимы пространства имен
 - •8.6.2. Using-объявления
 - •8.6.3. Using-директивы
 - •8.6.4. Стандартное пространство имен std
 - •9. Перегруженные функции
 - •9.1. Объявления перегруженных функций
 - •9.1.1. Зачем нужно перегружать имя функции
 - •9.1.2. Как перегрузить имя функции
 - •9.1.3. Когда не надо перегружать имя функции
 - •9.1.4. Перегрузка и область видимости a
 - •9.1.5. Директива extern "c" и перегруженные функции a
 - •9.1.6. Указатели на перегруженные функции a
 - •9.1.7. Безопасное связывание a
 - •9.2. Три шага разрешения перегрузки
 - •9.3. Преобразования типов аргументов a
 - •9.3.1. Подробнее о точном соответствии
 - •9.3.2. Подробнее о расширении типов
 - •9.3.3. Подробнее о стандартном преобразовании
 - •9.3.4. Ссылки
 - •9.4. Детали разрешения перегрузки функций
 - •9.4.1. Функции-кандидаты
 - •9.4.2. Устоявшие функции
 - •9.4.3. Наилучшая из устоявших функция
 - •9.4.4. Аргументы со значениями по умолчанию
 - •10. Шаблоны функций
 - •10.1. Определение шаблона функции
 - •10.2. Конкретизация шаблона функции
 - •10.3. Вывод аргументов шаблона а
 - •10.4. Явное задание аргументов шаблона a
 - •10.5. Модели компиляции шаблонов а
 - •10.5.1. Модель компиляции с включением
 - •10.5.2. Модель компиляции с разделением
 - •10.5.3. Явные объявления конкретизации
 - •10.6. Явная специализация шаблона а
 - •10.7. Перегрузка шаблонов функций а
 - •10.8. Разрешение перегрузки при конкретизации a
 - •10.9. Разрешение имен в определениях шаблонов а
 - •10.10. Пространства имен и шаблоны функций а
 - •10.11. Пример шаблона функции
 - •11. Обработка исключений
 - •11.1. Возбуждение исключения
 - •11.3. Перехват исключений
 - •11.3.1. Объекты-исключения
 - •11.3.2. Раскрутка стека
 - •11.3.3. Повторное возбуждение исключения
 - •11.3.4. Перехват всех исключений
 - •11.4. Спецификации исключений
 - •11.4.1. Спецификации исключений и указатели на функции
 - •11.5. Исключения и вопросы проектирования
 - •12. Обобщенные алгоритмы
 - •12.1. Краткий обзор
 - •12.2. Использование обобщенных алгоритмов
 - •12.3. Объекты-функции
 - •12.3.1. Предопределенные объекты-функции
 - •12.3.2. Арифметические объекты-функции
 - •12.3.3. Сравнительные объекты-функции
 - •12.3.4. Логические объекты-функции
 - •12.3.5. Адаптеры функций для объектов-функций
 - •12.3.6. Реализация объекта-функции
 - •12.4. Еще раз об итераторах
 - •12.4.1. Итераторы вставки
 - •12.4.2. Обратные итераторы
 - •12.4.3. Потоковые итераторы
 - •12.4.4. Итератор istream_iterator
 - •12.4.5. Итератор ostream_iterator
 - •12.4.6. Пять категорий итераторов
 - •12.5. Обобщенные алгоритмы
 - •12.5.1. Алгоритмы поиска
 - •12.5.2. Алгоритмы сортировки и упорядочения
 - •12.5.3. Алгоритмы удаления и подстановки
 - •12.5.4. Алгоритмы перестановки
 - •12.5.9. Алгоритмы работы с хипом
 - •12.6. Когда нельзя использовать обобщенные алгоритмы
 - •12.6.1. Операция list_merge()
 - •12.6.2. Операция list::remove()
 - •12.6.3. Операция list::remove_if()
 - •12.6.4. Операция list::reverse()
 - •12.6.5. Операция list::sort()
 - •12.6.6. Операция list::splice()
 - •12.6.7. Операция list::unique()
 - •Часть IV
 - •13. Классы
 - •13.1. Определение класса
 - •13.1.1. Данные-члены
 - •13.1.2. Функции-члены
 - •13.1.3. Доступ к членам
 - •13.1.4. Друзья
 - •13.1.5. Объявление и определение класса
 - •13.2. Объекты классов
 - •13.3. Функции-члены класса
 - •13.3.1. Когда использовать встроенные функции-члены
 - •13.3.2. Доступ к членам класса
 - •13.3.3. Закрытые и открытые функции-члены
 - •13.3.4. Специальные функции-члены
 - •13.3.5. Функции-члены со спецификаторами const и volatile
 - •13.3.6. Объявление mutable
 - •13.4. Неявный указатель this
 - •13.4.1. Когда использовать указатель this
 - •13.5. Статические члены класса
 - •13.5.1. Статические функции-члены
 - •13.6. Указатель на член класса
 - •13.6.1. Тип члена класса
 - •13.6.2. Работа с указателями на члены класса
 - •13.6.3. Указатели на статические члены класса
 - •13.7. Объединение – класс, экономящий память
 - •13.8. Битовое поле – член, экономящий память
 - •13.9. Область видимости класса a
 - •13.9.1. Разрешение имен в области видимости класса
 - •13.10. Вложенные классы a
 - •13.10.1. Разрешение имен в области видимости вложенного класса
 - •13.11. Классы как члены пространства имен a
 - •13.12. Локальные классы a
 - •14. Инициализация, присваивание и уничтожение класса
 - •14.1. Инициализация класса
 - •14.2. Конструктор класса
 - •14.2.1. Конструктор по умолчанию
 - •14.2.2. Ограничение прав на создание объекта
 - •14.2.3. Копирующий конструктор
 - •14.3. Деструктор класса
 - •14.3.1. Явный вызов деструктора
 - •14.3.2. Опасность увеличения размера программы
 - •14.4. Массивы и векторы объектов
 - •14.4.1. Инициализация массива, распределенного из хипа a
 - •14.4.2. Вектор объектов
 - •14.5. Список инициализации членов
 - •14.6. Почленная инициализация a
 - •14.6.1. Инициализация члена, являющегося объектом класса
 - •14.7. Почленное присваивание a
 - •14.8. Соображения эффективности a
 - •15. Перегруженные операторы и определенные пользователем преобразования
 - •15.1. Перегрузка операторов
 - •15.1.1. Члены и не члены класса
 - •15.1.2. Имена перегруженных операторов
 - •15.1.3. Разработка перегруженных операторов
 - •15.2. Друзья
 - •15.4. Оператор взятия индекса
 - •15.5. Оператор вызова функции
 - •15.6. Оператор “стрелка”
 - •15.7. Операторы инкремента и декремента
 - •15.8. Операторы new и delete
 - •15.8.1. Операторы new[ ] и delete [ ]
 - •15.8.2. Оператор размещения new() и оператор delete()
 - •15.9. Определенные пользователем преобразования
 - •15.9.1. Конвертеры
 - •15.9.2. Конструктор как конвертер
 - •15.10. Выбор преобразования a
 - •15.10.1. Еще раз о разрешении перегрузки функций
 - •15.10.2. Функции-кандидаты
 - •15.10.3. Функции-кандидаты для вызова функции в области видимости класса
 - •15.10.4. Ранжирование последовательностей определенных пользователем преобразований
 - •15.11. Разрешение перегрузки и функции-члены a
 - •15.11.1. Объявления перегруженных функций-членов
 - •15.11.2. Функции-кандидаты
 - •15.11.3. Устоявшие функции
 - •15.12. Разрешение перегрузки и операторы a
 - •15.12.1. Операторные функции-кандидаты
 - •15.12.2. Устоявшие функции
 - •15.12.3. Неоднозначность
 - •16. Шаблоны классов
 - •16.1. Определение шаблона класса
 - •16.1.1. Определения шаблонов классов Queue и QueueItem
 - •16.2. Конкретизация шаблона класса
 - •16.2.1. Аргументы шаблона для параметров-констант
 - •16.3. Функции-члены шаблонов классов
 - •16.3.1. Функции-члены шаблонов Queue и QueueItem
 - •16.4. Объявления друзей в шаблонах классов
 - •16.4.1. Объявления друзей в шаблонах Queue и QueueItem
 - •16.5. Статические члены шаблонов класса
 - •16.6. Вложенные типы шаблонов классов
 - •16.7. Шаблоны-члены
 - •16.8. Шаблоны классов и модель компиляции a
 - •16.8.1. Модель компиляции с включением
 - •16.8.2. Модель компиляции с разделением
 - •16.8.3. Явные объявления конкретизации
 - •16.9. Специализации шаблонов классов a
 - •16.10. Частичные специализации шаблонов классов a
 - •16.11. Разрешение имен в шаблонах классов a
 - •16.12. Пространства имен и шаблоны классов
 - •16.13. Шаблон класса Array
 - •Часть V
 - •17. Наследование и подтипизация классов
 - •17.1. Определение иерархии классов
 - •17.1.1. Объектно-ориентированное проектирование
 - •17.2. Идентификация членов иерархии
 - •17.2.1. Определение базового класса
 - •17.2.2. Определение производных классов
 - •17.2.3. Резюме
 - •17.3. Доступ к членам базового класса
 - •17.4. Конструирование базового и производного классов
 - •17.4.1. Конструктор базового класса
 - •17.4.2. Конструктор производного класса
 - •17.4.3. Альтернативная иерархия классов
 - •17.4.4. Отложенное обнаружение ошибок
 - •17.4.5. Деструкторы
 - •17.5. Виртуальные функции в базовом и производном классах
 - •17.5.1. Виртуальный ввод/вывод
 - •17.5.2. Чисто виртуальные функции
 - •17.5.3. Статический вызов виртуальной функции
 - •17.5.4. Виртуальные функции и аргументы по умолчанию
 - •17.5.5. Виртуальные деструкторы
 - •17.5.6. Виртуальная функция eval()
 - •17.5.7. Почти виртуальный оператор new
 - •17.5.8. Виртуальные функции, конструкторы и деструкторы
 - •17.6. Почленная инициализация и присваивание a
 - •17.7. Управляющий класс UserQuery
 - •17.7.1. Определение класса UserQuery
 - •17.8. Соберем все вместе
 - •18. Множественное и виртуальное наследование
 - •18.1. Готовим сцену
 - •18.2. Множественное наследование
 - •18.3. Открытое, закрытое и защищенное наследование
 - •18.3.1. Наследование и композиция
 - •18.3.2. Открытие отдельных членов
 - •18.3.3. Защищенное наследование
 - •18.3.4. Композиция объектов
 - •18.4. Область видимости класса и наследование
 - •18.4.1. Область видимости класса при множественном наследовании
 - •18.5. Виртуальное наследование a
 - •18.5.1. Объявление виртуального базового класса
 - •18.5.2. Специальная семантика инициализации
 - •18.5.3. Порядок вызова конструкторов и деструкторов
 - •18.5.4. Видимость членов виртуального базового класса
 - •18.6. Пример множественного виртуального наследования a
 - •18.6.1. Порождение класса, контролирующего выход за границы массива
 - •18.6.2. Порождение класса отсортированного массива
 - •18.6.3. Класс массива с множественным наследованием
 - •19.1. Идентификация типов во время выполнения
 - •19.1.1. Оператор dynamic_cast
 - •19.1.2. Оператор typeid
 - •19.1.3. Класс type_info
 - •19.2. Исключения и наследование
 - •19.2.1. Исключения, определенные как иерархии классов
 - •19.2.2. Возбуждение исключения типа класса
 - •19.2.3. Обработка исключения типа класса
 - •19.2.4. Объекты-исключения и виртуальные функции
 - •19.2.5. Раскрутка стека и вызов деструкторов
 - •19.2.6. Спецификации исключений
 - •19.2.7. Конструкторы и функциональные try-блоки
 - •19.3. Разрешение перегрузки и наследование a
 - •19.3.1. Функции-кандидаты
 - •19.3.2. Устоявшие функции и последовательности пользовательских преобразований
 - •19.3.3. Наилучшая из устоявших функций
 - •20. Библиотека iostream
 - •20.2. Ввод
 - •20.2.1. Строковый ввод
 - •20.3. Дополнительные операторы ввода/вывода
 - •20.4. Перегрузка оператора вывода
 - •20.5. Перегрузка оператора ввода
 - •20.6. Файловый ввод/вывод
 - •20.7. Состояния потока
 - •20.8. Строковые потоки
 - •20.9. Состояние формата
 - •20.10. Сильно типизированная библиотека
 - •21. Обобщенные алгоритмы в алфавитном порядке
 - •Алгоритм accumulate()
 - •Алгоритм adjacent_difference()
 - •Алгоритм adjacent_find()
 - •Алгоритм binary_search()
 - •Алгоритм copy()
 - •Алгоритм copy_backward()
 - •Алгоритм count()
 - •Алгоритм count_if()
 - •Алгоритм equal()
 - •Алгоритм equal_range()
 - •Алгоритм fill()
 - •Алгоритм fill_n()
 - •Алгоритм find()
 - •Алгоритм find_if()
 - •Алгоритм find_end()
 - •Алгоритм find_first_of()
 - •Алгоритм for_each()
 - •Алгоритм generate()
 - •Алгоритм generate_n()
 - •Алгоритм includes()
 - •Алгоритм inner_product()
 - •Алгоритм inplace_merge()
 - •Алгоритм iter_swap()
 - •Алгоритм lexicographical_compare()
 - •Алгоритм lower_bound()
 - •Алгоритм max()
 - •Алгоритм max_element()
 - •Алгоритм min()
 - •Алгоритм min_element()
 - •Алгоритм merge()
 - •Алгоритм mismatch()
 - •Алгоритм next_permutation()
 - •Алгоритм nth_element()
 - •Алгоритм partial_sort()
 - •Алгоритм partial_sort_copy()
 - •Алгоритм partial_sum()
 - •Алгоритм partition()
 - •Алгоритм prev_permutation()
 - •Алгоритм random_shuffle()
 - •Алгоритм remove()
 - •Алгоритм remove_copy()
 - •Алгоритм remove_if()
 - •Алгоритм remove_copy_if()
 - •Алгоритм replace()
 - •Алгоритм replace_copy()
 - •Алгоритм replace_if()
 - •Алгоритм replace_copy_if()
 - •Алгоритм reverse()
 - •Алгоритм reverse_copy()
 - •Алгоритм rotate()
 - •Алгоритм rotate_copy()
 - •Алгоритм search()
 - •Алгоритм search_n()
 - •Алгоритм set_difference()
 - •Алгоритм set_intersection()
 - •Алгоритм set_symmetric_difference()
 - •Алгоритм set_union()
 - •Алгоритм sort()
 - •Алгоритм stable_partition()
 - •Алгоритм stable_sort()
 - •Алгоритм swap()
 - •Алгоритм swap_ranges()
 - •Алгоритм transform()
 - •Алгоритм unique()
 - •Алгоритм unique_copy()
 - •Алгоритм upper_bound()
 - •Алгоритмы для работы с хипом
 - •Алгоритм make_heap()
 - •Алгоритм pop_heap()
 - •Алгоритм push_heap()
 - •Алгоритм sort_heap()
 
7.3.1. Параметры-ссылки
Использование ссылок в качестве параметров модифицирует стандартный механизм передачи по значению. При такой передаче функция манипулирует локальными копиями аргументов. Используя параметры-ссылки, она получает l-значения своих аргументов и может изменять их.
В каких случаях применение параметров-ссылок оправданно? Во-первых, тогда, когда без использования ссылок пришлось бы менять типы параметров на указатели (см. приведенную выше функцию swap()). Во-вторых, при необходимости вернуть из функции несколько значений. В-третьих, для передачи большого объекта типа класса. Рассмотрим два последних случая подробнее.
Как пример функции, использующей параметр-ссылку для возврата дополнительного значения, возьмем look_up(), которая будет искать заданную величину в векторе целых чисел. В случае успеха look_up() вернет итератор, указывающий на найденный элемент, иначе – на элемент, расположенный за конечным. Если величина содержится в векторе несколько раз, итератор будет указывать на первое вхождение. Кроме того, дополнительный параметр-ссылка occurs возвращает количество найденных элементов.
#include <vector>
// параметр-ссылка 'occurs'
// содержит второе возвращаемое значение
vector<int>::const_iterator look_up(
const vector<int> &vec,
int value, // искомое значение
int &occurs ) // количество вхождений
{
// res_iter инициализируется значением
// следующего за конечным элемента
vector<int>::const_iterator res_iter = vec.end();
occurs = 0;
for ( vector<int>::const_iterator iter = vec.begin();
iter != vec.end();
++iter )
if ( *iter == value )
{
if ( res_iter == vec.end() )
res_iter = iter;
++occurs;
}
return res_iter;
}
Третий случай, когда использование параметра-ссылки может быть полезно, – это большой объект типа класса в качестве аргумента. При передаче по значению объект будет копироваться целиком при каждом вызове функции, что для больших объектов может привести к потере эффективности. Используя параметр-ссылку, функция получает доступ к той области памяти, где размещен сам объект, без создания дополнительной копии. Например:
class Huge { public: double stuff[1000]; };
extern int calc( const Huge & );
int main() {
Huge table[ 1000 ];
// ... инициализация table
int sum = 0;
for ( int ix=0; ix < 1000; ++ix )
// calc() ссылается на элемент массива
// типа Huge
sum += calc( tab1e[ix] );
// ...
}
Может возникнуть желание использовать параметр-ссылку, чтобы избежать создания копии большого объекта, но в то же время не дать вызываемой функции возможности изменять значение аргумента. Если параметр-ссылка не должен модифицироваться внутри функции, то стоит объявить его как ссылку на константу. В такой ситуации компилятор способен распознать и пресечь попытку непреднамеренного изменения значения аргумента.
В следующем примере нарушается константность параметра xx функции foo(). Поскольку параметр функции foo_bar() не является ссылкой на константу, то нет гарантии, что вызов foo_bar() не изменит значения аргумента. Компилятор сигнализирует об ошибке:
class X;
extern int foo_bar( X& );
int foo( const X& xx ) {
// ошибка: константа передается
// функции с параметром неконстантного типа
return foo_bar( xx );
}
Для того чтобы программа компилировалась, мы должны изменить тип параметра foo_bar(). Подойдет любой из следующих двух вариантов:
extern int foo_bar( const X& );
extern int foo_bar( X ); // передача по значению
Вместо этого можно передать копию xx, которую позволено менять:
int foo( const X &xx ) {
// ...
X x2 = xx; // создать копию значения
// foo_bar() может поменять x2,
// xx останется нетронутым
return foo_bar( x2 ); // правильно
}
Параметр-ссылка может именовать любой встроенный тип данных. В частности, разрешается объявить параметр как ссылку на указатель, если программист хочет изменить значение самого указателя, а не объекта, который он адресует. Вот пример функции, обменивающей друг с другом значения двух указателей:
void ptrswap( int *&vl, int *&v2 ) {
int *trnp = v2;
v2 = vl;
vl = tmp;
}
Объявление
int *&v1;
должно читаться справа налево: v1 является ссылкой на указатель на объект типа int. Модифицируем функцию main(), которая вызывала rswap(), для проверки работы ptrswap():
#include <iostream>
void ptrswap( int *&vl, int *&v2 );
int main() {
int i = 10;
int j = 20;
int *pi = &i;
int *pj = &j;
cout << "Перед ptrswap():\tpi: "
<< *pi << "\tpj: " << *pj << endl;
ptrswap( pi, pj );
cout << "После ptrswap():\tpi: "
<< *pi << "\tpj: " << pj << endl;
return 0;
}
Вот результат работы программы:
Перед ptrswap(): pi: 10 pj: 20
После ptrswap(): pi: 20 pj: 10
