Главная | Обратная связь | Поможем написать вашу работу!
МегаЛекции

Классы, содержащие объекты других классов




Элементы - данные некоторого класса могут быть объектами других классов, содержащих свои конструкторы и деструкторы.

В объектно-ориентированной методологии известно такое понятие HASA relationship.

Инициализация элементов-объектов осуществляется через список инициализации (constructor initializer).

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

имя_члена (список аргументов).

Список аргументов должен соответствовать какому-нибудь из конструкторов класса к которому он принадлежит. Именно этот конструктор и будет вызываться для таких членов-объектов класса.

// класс с объектами-членами другого класса

class A {

........... public: A(int n=0) {...}; ~A() {...};

};

class B {

........... public: B(double x=0) {...}; ~B() {...};

};

class D { const A a; B b;

public: D(double x,int i); D(double x); D(); ~D();

};

// реализация

D::D(double x,int i):b(x),a(i)

{....... }

D::D(double x):b(x) {....... }

D::D():b(0) {....... }

В этом примере класс D создает два объекта классов A и B. Для инициализации a и b используется список инициализации. При использовании классов агрегатов следует учесть, что конструкторы членов-объектов класса вызываются раньше, чем для класса владельца.

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

В нашем случае D с двумя переменными первым будет вызывать конструктор объекта a.

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

Аргументы объектов в списке инициализации могут быть сколь угодно сложными.

Список инициализации членов является единственным способом инициализации константных объектов членов-класса, ссылок, объектов с защищенными данными.

 

 

Создание объектов с различным временем жизни

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

Время жизни объектов определяется классом памяти.

Статические объекты создаются и инициализируются на момент запуска программы в сегменте данных и существуют до ее остановки, не меняя своего месторасположения в памяти. Конструкторы таких объектов называются цельными. Конструкторы для статических объектов могут вызываться до main(). Деструкторы вызываются по окончании программы в порядке обратном вызове конструкторов.

Автоматические объекты создаются и инициализируются в стеке в момент входа в блок и завершают свое существование при выходе из блока. Конструктор для автоматических объектов вызывается неявно при каждом определенном входе в блок или в функцию. Деструктор для каждого автоматического объекта также вызываются неявно, при выходе из блока или функции, но в порядке обратном вызову конструкторов.

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

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

Point2D p1=new Poinr2D(5.5,10.1);

................................

delete p1;

 

Массивы объектов класса

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

Point2D P1[3]={Point2D(2,4),Point2D(3,3),Point2D(4,6)};

Point2D P2[3]={Point2D(5),Point2D(4),Point2D(3)};

Point2D P3[3]={5,4,3};

Point2D P4[3]={Point2D(4),5,Point2D(3,1)};

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

Если у класса конструктор операции new [], можно создать массив в динамической области памяти. Инициализация такого массива не допустима.

Point2D *pArray= new Point2D[20];

...........

delete [] pArray;

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

table tbl[10];

будет создан массив из 10 таблиц, каждая из которых инициализируется вызовом table::table(15), поскольку вызов table::table() будет происходить с фактическим параметром 15.

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

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

void f(){ table* t1 = new table; table* t2 = new table[10]; delete t1; // удаляется одна таблица delete t2; // неприятность: // на самом деле удаляется 10 таблиц}

В данном случае программист должен указать, что t2 - указатель на массив:

void g(int sz){ table* t1 = new table; table* t2 = new table[sz]; delete t1; delete[] t2;} Функция размещения хранит число элементов для каждого размещаемого массива. Требование использовать для удаления массивов только операцию delete[] освобождает функцию размещения от обязанности хранить счетчики числа элементов для каждого массива. Исполнение такой обязанности в реализациях С++ вызывало бы существенные потери времени и памяти и нарушило совместимость с С.

Особенности копирования объектов

Конструктор копирования

Конструктор копирования - это специальный вид конструктора, получающий в качестве единственного параметра указатель на объект этого же класса:

T::T(const T&) {... /* Тело конструктора */ }

где T - имя класса. Этот конструктор вызывается в тех случаях, когда новый объект создается путем копирования существующего:

  • при описании нового объекта с инициализацией другим объектом;
  • при передаче объекта в функцию по значению;
  • при возврате объекта из функции.

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

Запишем конструктор копирования для класса monster. Поскольку в нем есть поле name, содержащее указатель на строку символов, конструктор копирования должен выделять память под новую строку и копировать в нее исходную:

monster::monster(const monster &M){if (M.name) { name = new char [strlen(M.name) + 1]; strcpy(name, M.name); } else name = 0;health = M.health; ammo = M.ammo; skin = M.skin;}...monster Vasia (blue); monster Super = Vasia; // Работает конструктор копированияmonster *m = new monster ("Ork");monster Green = *m; // Работает конструктор копирования

 

 

Поделиться:





Воспользуйтесь поиском по сайту:



©2015 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...