Указатели и ссылки
Часть раздела Объектно-ориентированное программирование путешествия по C++ на Coddy. Урок 13 из 104.
Теперь, когда ты понимаешь стековую и динамическую память, давай изучим инструменты, которые позволяют напрямую работать с ячейками памяти: pointers и references.
pointer хранит memory address другой переменной. Его объявляют с помощью * и получают address с помощью &.
int value = 42;
int* ptr = &value; // ptr хранит адрес value
std::cout << ptr; // Выводит адрес памяти
std::cout << *ptr; // Разыменование: выводит 42reference — это alias для существующей переменной. После связывания он всегда ссылается на эту переменную. Объявить его можно с помощью &.
int value = 42;
int& ref = value; // ref является псевдонимом для value
ref = 100; // Изменяет value на 100
std::cout << value; // Выводит 100Ключевые различия:
| Указатели | Ссылки |
|---|---|
| Могут быть null | Должны быть инициализированы |
| Могут быть переназначены | Не могут быть переназначены |
Используйте *, чтобы получить доступ к значению | Получайте доступ к значению directly |
| Могут указывать в никуда | Всегда действительны |
both необходимы для эффективной передачи объектов в функции без копирования и для работы с памятью, выделенной в куче. Ссылки безопаснее и проще, тогда как pointers предоставляют больше гибкости, когда нужно переназначить их или проверить на null.
Задание
ЛегкоДавайте создадим простую систему манипуляции значениями, демонстрирующую, как pointer и reference по-разному работают при изменении данных.
Вы создадите два файла, чтобы организовать свой код:
ValueOps.h: define three functions, которые изменяют значения типа integer разными способами:doubleByPointer(int* ptr): takes pointer и удваивает значение, на которое он указываетtripleByReference(int& ref): takes reference и утраивает значениеswapValues(int* a, int* b): takes two pointers и меняет местами значения, на которые они указывают
main.cpp: Read two integers from input, затем продемонстрируйте работу pointers и references:- Выведите Original values:
"Original: <first> <second>" - Используйте
doubleByPointerдля first value, затем выведите:"After double: <first>" - Используйте
tripleByReferenceдля second value, затем выведите:"After triple: <second>" - Используйте
swapValues, чтобы поменять местами both values, затем выведите:"After swap: <first> <second>"
- Выведите Original values:
При вызове functions с pointers не забудьте использовать оператор взятия address (&), чтобы передать address переменной. References работают более естественно: просто передайте переменную directly.
Подключите свой header file в main.cpp с помощью #include "ValueOps.h".
Попробуйте сами
#include <iostream>
#include "ValueOps.h"
using namespace std;
int main() {
// Прочитать два целых числа из ввода
int first, second;
cin >> first;
cin >> second;
// Вывести исходные значения
cout << "Original: " << first << " " << second << endl;
// TODO: Использовать doubleByPointer для первого значения (передать адрес с помощью &)
// TODO: Вывести после удвоения
// TODO: Использовать tripleByReference для второго значения (передать переменную напрямую)
// TODO: Вывести после утроения
// TODO: Использовать swapValues для обмена обоих значений (передать адреса с помощью &)
// TODO: Вывести после обмена
return 0;
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Внешние файлыСборка и компиляция C++Заголовочные файлы и файлы исходного кодаПространства имен и область видимостиВведение в ООП на C++Классы и объектыУказатель 'this'Методы (функции-члены)Атрибуты (члены данных)Основы конструкторов и деструкторовИтоги — Простой калькулятор4Свойства классов
Члены экземпляра против статическихГеттеры и сеттерыКонстантные функции-членыКлючевое слово mutableСтатические методы и переменныеДружественные функции и классыИтоги — Менеджер банковских счетов7Наследование
Основы наследованияУровни доступа при наследованииПорядок вызова конструкторов и деструкторовПереопределение методовВиртуальные функции и VTableМножественное наследованиеВиртуальное наследованиеИтоги — Иерархия сотрудников10Обзор STL
Обзор и философия STLКонтейнеры STLИтераторыАлгоритмы STLФункторы и лямбда-выраженияИтоги: частота слов13Паттерны проектирования. Часть 1
Введение в паттерны проектированияПаттерн SingletonFactory и Abstract FactoryПаттерн BuilderПаттерн ObserverПаттерн Strategy2Управление памятью
Стек и кучаУказатели и ссылкиДинамическая память (new/delete)Умные указатели в C++RAII в C++Итоги — Менеджер динамического массива5Инкапсуляция
Спецификаторы доступа в C++Спецификаторы доступа: подробный разборСокрытие данныхStruct против ClassВложенные и внутренние классыИтоги — Система учета студентов8Полиморфизм
Полиморфизм компиляции и времени выполненияПерегрузка функцийВиртуальные функции: повторениеЧистые виртуальные функцииАбстрактные классыПроектирование интерфейсов на C++Dynamic Casting и RTTIИтоги: Калькулятор фигур11Продвинутые концепции ООП
Композиция против наследованияМиксины через CRTPИдиома PimplСтирание типовEnum Classes и строгая типизацияОбработка исключений в ООППользовательские иерархии исключений14Паттерны проектирования. Часть 2
Паттерн КомандаПаттерн АдаптерПаттерн ДекораторПаттерн Шаблонный методПаттерн СостояниеПаттерн КомпоновщикRAII как паттерн3Конструкторы и деструкторы
Конструктор по умолчаниюПараметризованный конструкторКонструктор копированияКонструктор перемещенияСписки инициализации конструктораДелегирующие конструкторыГлубокое погружение в деструкторыПравило трех / пяти / нуляПовторение — класс String6Перегрузка операторов
Введение в перегрузку операторовПерегрузка арифметических операторовПерегрузка операторов сравненияОператоры потоковПерегрузка оператора присваиванияПерегрузка операторов [] и ()Операторы преобразования типовИтоги — класс Matrix9Шаблоны
Шаблоны функцийШаблоны классовСпециализация шаблоновВариативные шаблоныОсновы SFINAE и Type TraitsИтоги — Обобщенный контейнерПотренируйтесь самостоятельно: Онлайн-компилятор C++