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

20. Динамическая и статическая инициализация переменных и объектов.

Статическая инициализация-это процесс, в котором значение инициализации известно во время компиляции.

Динамическая инициализация-это процесс, в котором значение инициализации не известно во время компиляции. Он вычисляется во время выполнения для инициализации переменной.

Таким образом, существует два вида инициализации:

  • Статическая инициализация : либо нулевая инициализация, либо инициализация с постоянным выражением

  • Любая другая инициализация является динамической инициализацией. Пример:

Динамические объекты существуют, пока не будут удалены явным образом. Динамические объекты размещаются в динамической памяти (free store).

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

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

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

Статический блок — это, в сущности, конструктор для всего класса. Он ставится между определениями полей и функциями класса. Команды будут выполняться в одном из двух случаев, том, который наступит раньше:

- При создании первого объекта класса в процессе работы программы, перед запуском конструктора.

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

То есть код выполняется при первой загрузке класса.

Динамический блок представляет собой дополнение к конструктору. Он ставится между определениями полей и функциями класса. Команды будут выполняться при создании объекта. Динамический блок — это добавка для упрощения написания конструктора, и он не приносит дополнительной функциональности. Он позволяет сэкономить создание функции запуска и добавление её вызова из всех конструкторов.

42. Дружественные функции класса. Перегрузка функций и методов. Особенности перегрузки операторов как метода класса и как дружественной функции.

В С++ существует возможность разрешить доступ к закрытым элементам класса, методом, который не является элементом этого класса. Для этого достаточно объявить эти методы дружественными по отношению к рассматриваемому классу. Чтобы сделать функцию другом класса, включите ее прототип в public-раздел с ключевым словом friend. Ключевое слово friend предоставляет доступ ко всем его элементам. Один метод может быть другом для нескольких классов.

Одна из причин, почему язык С++ допускает существование friend-методов, связана с ситуациями, когда два класса должны использовать одну и ту же функцию. Метод friend вызывается обычным образом, т.е. без привязки к объекту и использования «.». Т.к. они не являются методами-элементами класса, то при вызове не нужно указывать имя объекта, для которого он вызывается. Обычно friend – методу передается в качестве параметров один или несколько объектов класса(ов), для которого(ых) он является другом. Существуют определенные обстоятельства, при которых статус метода-«друга» имеет большое значение.

  1. Friend-методы могут быть полезны для перегрузки операторов.

  2. Они упрощают создание некоторых функций ввода-вывода.

  3. В некоторых случаях два (или больше) класса могут содержать члены, которые находятся во взаимной связи с другими частями программы.

Опережающее объявление класса предназначено для объявления имени классового типа до определения самого класса. Чтобы создать опережающее объявление класса, достаточно написать: class имя_класса; «Друг» одного класса может быть элементом другого класса.

Отметим основные свойства и правила использования спецификатора friend:

− friend-функции не являются компонентами класса, но имеют доступ ко всем его компонентам независимо от их атрибута доступа;

− friend-функции не имеют указателя this;

− friend-функции не наследуются в производных классах;

− отношение friend не является ни симметричным (т. е. если класс А friend классу В, то это не означает, что В также является friend классу А), ни транзитивным (т. е. если A friend B и B friend C, то не следует, что A friend C);

− друзьями класса можно определить перегруженные функции. Каждая перегруженная функция, используемая как friend для некоторого класса, должна быть явно объявлена в классе со спецификатором friend.

Перегрузка функций — это особенность C++, которая позволяет определять несколько функций с одним и тем же именем, но с разными параметрами. Перегрузка функций нужна для того, чтобы избежать дублирования имён функций, выполняющих сходные действия, но с различной программной логикой.

Пример: int fun( int a, int b) double fun(double a, double b)

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

Для определения того, какую версию перегруженной функции вызвать, компилятор использует тип и/или количество аргументов. Таким образом, перегруженные функции должны отличаться типами и/или числом параметров.

Особенности:

Есть три разных способа перегрузки операторов:

· через дружественные функции;

· через обычные функции;

· через методы класса.

При перегрузке бинарного оператора с использованием метода класса ей передается явным образом только один аргумент. Второй же неявно передается через указатель this.

Friend-функция необходима для перегрузки операторов вывода в поток и считывания из потоков.

Перегрузка конструкторов очень схожа с перегрузкой функций. Конструкторов в определяемом классе может быть несколько – по мере необходимости. Они должны иметь одинаковое имя, идентичное имени класса и обязательно должны отличаться сигнатурой.

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

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

Применение динамической инициализации к конструкторам.

Подобно простым переменным, объекты можно инициализировать динамически при их создании. Это средство позволяет создавать объект нужного типа с использованием информации, которая становится известной только во время выполнения программы (т.е. не константные значения, а значения, введенные с клавиатуры (cin)).

Наличие множества форматов инициализации избавляет программиста от выполнения дополнительных преобразований при инициализации объектов.

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

Загромождение кода конструкторами для обработки редко возникающих ситуаций оказывает, как правило, дестабилизирующее влияние на программу.

Узелок на память. Разрабатывая перегруженные конструкторы, необходимо определиться в том, какие ситуации важно предусмотреть, а какие можно и не учитывать.

22. Присваивание объектов. Понятие побитового копирования. Передача объектов в качестве аргументов функции. Особенности использования конструкторов, деструкторов при передаче объектов в качестве параметров.

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

По умолчанию все данные одного объекта присваиваются другому путем побитового копиро­вания. Однако возможно перегрузить оператор присваивания и определить некоторые другие процедуры присвоения.

Объекты могут быть переданы в функции тем же способом, что и переменные любого другого типа. Объекты передаются функциям с использованием стандартного механизма передачи по значению. Это означает, что создается копия объекта, которая и передается функции. Однако тот факт, что создается копия, означает по существу, что создается другой объект. В результате возникает вопрос, исполняется ли функция-конструктор объекта при создании копии и исполня­ется ли функция-деструктор, когда копия уничтожается. 

  При создании копии объекта для передачи ее в функцию конструктор объекта не вызывается. Однако, когда копия объекта внутри функции уничтожается, деструктор вызывается.

Новый объект служит точным дубликатом оригинала.

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

Способ порождения нового объекта — через так называемый копирующий конструктор.

Для локального объекта при выходе из функции будет вызван деструктор.

Если объект может оказаться «тяжёлым» или потенциально возможно его укрупнение в будущем, желательно использовать передачу объекта по ссылке. Это не только экономит память, но и время, исключая необходимость копирования.

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

23. Потенциальные проблемы при передаче объектов в качестве параметров. Возврат объектов функциями. Потенциальная проблема при возврате объектов функциями.

Способ порождения нового объекта — через так называемый конструктор копирования. В случае сложных типов (особенно, имеющих в атрибутах указатели на динамические данные) клонирующий конструктор, определённый по-умолчанию, требуется перегрузить собственным (или явно запретить через помещение его в private зону класса).

В случае передачи по константной ссылке компилятор является гарантом неприкосновенности переданного экземпляра.

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

Функция может возвращать объект в точку вызова. Когда функция возвращает объект, автоматически создается временный объект, содержащий возвращаемое значение. Именно этот объект фактически возвращается функцией. После того, как значение возвращено, этот объект уничтожается. Уничтожение временного объекта может вызывать неожиданные побочные эффекты в некоторых ситуациях. Например, если возвращае­мый функцией объект имеет деструктор, освобождающий динамически зарезервированную па­мять, то эта память будет освобождена даже в том случае, когда объект, получающий возвраща­емое значение, будет продолжать использовать ее. Также можно преодолеть эту проблему, для чего используется перегрузка оператора присваивания и определение конструктора копирования.