Классы, содержащие объекты других классов
Элементы - данные некоторого класса могут быть объектами других классов, содержащих свои конструкторы и деструкторы. В объектно-ориентированной методологии известно такое понятие 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 Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...
|