|
Программирование >> Инициализация объектов класса, структура
Screen *psa = new Screen[10]; В классе можно объявить также операторы new[]() и delete[]() для работы с массивами. Оператор-член new[]() должен возвращать значение типа void* и принимать в качестве class Screen { public: void *operator new[]( size t ); ... первого параметра значение типа size t. Вот его объявление для Screen: }; Когда с помощью new создается массив объектов типа класса, компилятор проверяет, определен ли в классе оператор new[](). Если да, то для выделения памяти под массив вызывается именно он, в противном случае - глобальный new[]() . В следующей инструкции в хипе создается массив из десяти объектов Screen: Screen *ps = new Screen[10]; В этом классе есть оператор new[]() , поэтому он и вызывается для выделения памяти. Его параметр size t автоматически инициализируется значением, равным объему памяти в байтах, необходимому для размещения десяти объектов Screen. Даже если в классе имеется оператор-член new[](), программист может вызвать для создания массива глобальный new[]() , воспользовавшись оператором разрешения глобальной области видимости: Screen *ps = ::new Screen[10]; Оператор delete() , являющийся членом класса, должен иметь тип void, а в качестве class Screen { public: void operator delete[]( void * ); первого параметра принимать void*. Вот как выглядит его объявление для Screen: }; Чтобы удалить массив объектов класса, delete должен вызываться следующим образом: delete[] ps; Когда операндом delete является указатель на объект типа класса, компилятор проверяет, определен ли в этом классе оператор delete[]() . Если да, то для освобождения памяти вызывается именно он, в противном случае - его глобальная версия. Параметр типа void* автоматически инициализируется значением адреса начала области памяти, в которой размещен массив. class Screen { public: заменяет void operator delete[]( void* ); void operator delete[]( void*, size должен иметь тип size t: }; Если второй параметр присутствует, то компилятор автоматически инициализирует его значением, равным объему отведенной под массив памяти в байтах. 15.8.2. Оператор размещения new() и оператор delete() Оператор-член new() может быть перегружен при условии, что все объявления имеют class Screen { public: void *operator new( size t ); void *operator new( size t, Screen * ); ... разные списки параметров. Первый параметр должен иметь тип size t: Даже если в классе имеется онератор-член delete[](), программист может вызвать глобальный delete [](), воспользовавшись оператором разрешения глобальной области видимости: ::delete[] ps; Добавление операторов new[]() или delete[]() в класс или удаление их оттуда не отражаются на пользовательском коде: вызовы как глобальных операторов, так и операторов-членов выглядят одинаково. При создании массива сначала вызывается new[]() для выделения необходимой памяти, а затем каждый элемент инициализируется с помощью конструктора по умолчанию. Если у класса есть хотя бы один конструктор, но нет конструктора по умолчанию, то вызов оператора new[]() считается ошибкой. Не существует синтаксической конструкции для задания инициализаторов элементов массива или аргументов конструктора класса при создании массива подобным образом. При уничтожении массива сначала вызывается деструктор класса для уничтожения элементов, а затем оператор delete[]() - для освобождения всей памяти. При этом важно использовать правильный синтаксис. Если в инструкции delete ps; ps указывает на массив объектов класса, то отсутствие квадратных скобок приведет к вызову деструктора лишь для первого элемента, хотя память будет освобождена полностью. У оператора-члена delete[]() может быть не один, а два параметра, при этом второй void func( Screen *start ) { Screen *ps = new (start) Screen; ... вызове new: Та часть выражения, которая находится после ключевого слова new и заключена в круглые скобки, представляет аргументы размещения. В примере выше вызывается оператор new() , принимающий два параметра. Первый автоматически инициализируется значением, равным размеру класса Screen в байтах, а второй - значением аргумента размещения start. Можно также перегружать и оператор-член delete(). Однако такой оператор никогда не вызывается из выражения delete. Перегруженный delete() неявно вызывается компилятором, если конструктор, вызванный при выполнении оператора new (это не опечатка, мы действительно имеем в виду new), возбуждает исключение. Рассмотрим использование delete() более внимательно. Последовательность действий при вычислении выражения Screen *ps = new ( start ) Screen; 1. Вызывается определенный в классе оператор new(size t, Screen*) . 2. Выз1вается конструктор по умолчанию класса Screen для инициализации созданного объекта. Переменная ps инициализируется адресом нового объекта Screen. Предположим, что оператор класса new(size t, Screen*) выделяет память с помощью глобального new() . Как разработчик может гарантировать, что память будет освобождена, если вызванн1й на шаге 2 конструктор возбуждает исключение? Чтобы защитить пользовательский код от утечки памяти, следует предоставить перегруженный оператор delete() , который вызывается только в подобной ситуации. Если в классе имеется перегруженный оператор с параметрами, типы которых соответствуют типам параметров new() , то компилятор автоматически вызывает его для освобождения памяти. Предположим, есть следующее выражение с оператором размещения new: Screen *ps = new (start) Screen; Если конструктор по умолчанию класса Screen возбуждает исключение, то компилятор ищет delete() в области видимости Screen. Чтобы такой оператор был найден, типы его параметров должны соответствовать типам параметров вызванного new() . Поскольку первый параметр new() всегда имеет тип size t, а оператора delete() - void*, то первые параметры при сравнении не учитываются. Компилятор ищет в классе Screen оператор delete() следующего вида: такова: Остальные параметры инициализируются аргументами размещения, заданными при
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0.001
При копировании материалов приветствуются ссылки. |