Скачиваний:
316
Добавлен:
28.03.2021
Размер:
378.53 Кб
Скачать

35. Особенности использования указателей и ссылок. Ссылки как параметры методов и как возвращаемые значения. Статические и динамические объекты.

Указатель на объект производного класса может быть неявно преобра­зован в указатель на объект базового класса, потому что объект производного класса «является» объектом базового класса.

Существует четыре возможных способа комбинирования и попарного со­поставления указателей и объектов базового и производного классов:

  1. Ссылка на объект базового класса с помощью указателя базового класса очевидна.

  2. Ссылка на объект производного класса с помощью указателя произ­водного класса очевидна.

  3. Ссылка на объект производного класса с помощью указателя базового класса не опасна, потому что объект производного класса является также и объектом своего базового класса. Если производится ссылка с помощью указателя базового класса на элементы, имеющиеся только в объектах производного класса, компилятор сообщит о синтаксической ошибке.

  4. Ссылка на объект базового класса с помощью указателя производ­ного класса является синтаксической ошибкой. Указатель производ­ного класса сначала должен быть приведен к типу указателя базового класса.

Приведение типа указателя базового класса к типу указателя производного класса может вызвать ошибки, если этот указатель используется затем для ссылки на объект базового класса, который не имеет требуемых элементов производного класса.

Ссылка — это неявный указатель.

При вызове по ссылке передаётся адрес аргумента. Такой тип передачи аргумента называется вызовом по ссылке. В этом случае в параметр копируется адрес аргумента (а не его значение). В пределах вызываемой подпрограммы этот адрес используется для доступа к реальному аргументу, заданному при ее вызове. Это значит, что изменения, внесенные в параметр, окажут воздействие на аргумент, используемый при вызове подпрограммы.

При использовании ссылочного параметра функции автоматически передается адрес (а не значение) аргумента. При выполнении кода функции, а именно при выполнении операций над ссылочным параметром, обеспечивается его автоматическое разыменование, и поэтому программисту не нужно использовать операторы, работающие с указателями. Ссылочный параметр объявляется с помощью символа, который должен предшествовать имени параметра в объявлении функции. Операции, выполняемые над ссылочным параметром, оказывают влияние на аргумент, используемый при вызове функции, а не на сам ссылочный параметр. Пример: void f(int &i);-обьявление функции, f(val);- вызов функции.

После создания ссылочный параметр автоматически ссылается (т.е. неявно указывает) на аргумент, используемый при вызове функции. Более того, при вызове функции не нужно применять к аргументу оператор. Кроме того, в теле функции ссылочный параметр используется непосредственно, т.е. без использования оператора. Все операции, включающие ссылочный параметр, автоматически выполняются над аргументом, используемым при вызове функции.

Присваивая некоторое значение ссылке, вы в действительности присваиваете это значение переменной, на которую указывает эта ссылка. Поэтому, применяя ссылку в качестве аргумента функции, при вызове функции вы в действительности используете такую переменную.

Если функция возвращает ссылку, это означает, что она возвращает неявный указатель на значение, передаваемое ею в инструкции return. Этот факт открывает поразительные возможности: функцию, оказывается, можно использовать в левой части инструкции присваивания

В C++ можно использовать различные типы объектов, которые различаются по использованию памяти. Так, глобальные объекты создаются при запуске программы и освобождаются при ее завершении. Локальные автоматические объекты создаются в блоке кода и удаляются, когда этот блок кода завершает работу. Локальные статические объекты создаются перед их первым использованием и освобождаются при завершении программы.

Глобальные, а также статические локальные объекты помещаются в статической памяти, а локальные автоматические объекты размещаются в стеке. Объекты в статической памяти и стеке создаются и удаляются компилятором. Статическая память очищается при завершении программы, а объекты из стека существуют, пока выполняется блок, в котором они определены.

В дополнение к этим типам в C++ можно создавать динамические объекты. Продолжительность их жизни не зависит от того, где они созданы. Динамические объекты существуют, пока не будут удалены явным образом. Динамические объекты размещаются в динамической памяти (free store).

Для управления динамическими объектами применяются операторы new и delete.

Оператор new выделяет место в динамической памяти для объекта и возвращает указатель на этот объект.

Оператор delete получает указатель на динамический объект и удаляет его из памяти.

Выделение памяти для динамического объекта:

Создание динамического объекта:

int *ptr = new int;

Оператор new создает новый объект типа int в динамической памяти и возвращает указатель на него. Значение такого объекта не определено.

Также можно инициализировать объект при создании:

int *p1 = new int(); // значение по умолчанию - 0

std::cout << "p1: " << *p1 << std::endl; // 0

int *p2 = new int(12);

std::cout << "p2: " << *p2 << std::endl; // 12

Освобождение памяти:

Динамические объекты будут существовать пока не будут явным образом удалены. И после завершения использования динамических объектов следует освободить их память с помощью оператора delete.

Также нередко имеет место ситуация, когда на один и тот же динамический объект указывают сразу несколько указателей. Если оператор delete применен к одному из указателей, то память объекта освобождается, и по второму указателю этот объект мы использовать уже не сможем. Если же после этого ко второму указателю применить оператор delete, то динамическая память может быть нарушена.