Поддержка абстракции данных




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

Инициализация и удаление

Когда представление типа скрыто, необходимо дать пользователю средствадля инициализации переменных этого типа. Простейшее решение - доиспользования переменной вызывать некоторую функцию для ее инициализации.Например: class vector { //... public: void init (init size); // вызов init () перед первым // использованием объекта vector //... }; void f () { vector v; // пока v нельзя использовать v.init (10); // теперь можно } Но это некрасивое и чреватое ошибками решение. Будет лучше, еслисоздатель типа определит для инициализации переменных некоторуюспециальную функцию. Если такая функция есть, то две независимые операцииразмещения и инициализации переменной совмещаются в одной (иногда ееназывают инсталляцией или просто построением). Функция инициализацииназывается конструктором. Конструктор выделяется среди всех прочих функцийданного класса тем, что имеет такое же имя, как и сам класс. Если объектынекоторого типа строятся нетривиально, то нужна еще одна дополнительнаяоперация для удаления их после последнего использования. Функция удаленияв С++ называется деструктором. Деструктор имеет то же имя, что и егокласс, но перед ним стоит символ ~ (в С++ этот символ используется дляоперации дополнения). Приведем пример: class vector { int sz; // число элементов int * v; // указатель на целые public: vector (int); // конструктор ~vector (); // деструктор int& operator [] (int index); // операция индексации }; Конструктор класса vector можно использовать для контроля над ошибкамии выделения памяти: vector::vector (int s) { if (s <= 0) error ("недопустимый размер вектора"); sz = s; v = new int [ s ]; // разместить массив из s целых } Деструктор класса vector освобождает использовавшуюся память: vector::~vector () { delete [] v; // освободить массив, на который // настроен указатель v } От реализации С++ не требуется освобождения выделенной с помощью newпамяти, если на нее больше не ссылается ни один указатель (иными словами,не требуется автоматическая "сборка мусора"). В замен этого можно безвмешательства пользователя определить в классе собственные функцииуправления памятью. Это типичный способ применения конструкторов идеструкторов, хотя есть много не связанных с управлением памятьюприменений этих функций (см., например, $$9.4).

Присваивание и инициализация

Для многих типов задача управления ими сводится к построению иуничтожению связанных с ними объектов, но есть типы, для которых этогомало. Иногда необходимо управлять всеми операциями копирования. Вернемсяк классу vector: void f () { vector v1 (100); vector v2 = v1; // построение нового вектора v2, // инициализируемого v1 v1 = v2; // v2 присваивается v1 //... } Должна быть возможность определить интерпретацию операцийинициализации v2 и присваивания v1. Например, в описании: class vector { int * v; int sz; public: //... void operator = (const vector &); // присваивание vector (const vector &); // инициализация }; указывается, что присваивание и инициализация объектов типа vectorдолжны выполняться с помощью определенных пользователем операций.Присваивание можно определить так: void vector::operator = (const vector & a) // контроль размера и копирование элементов { if (sz!= a.sz) error ("недопустимый размер вектора для ="); for (int i = 0; i < sz; i++) v [ i ] = a.v [ i ]; } Поскольку эта операция использует для присваивания "старое значение"вектора, операция инициализации должна задаваться другой функцией,например, такой: vector::vector (const vector & a) // инициализация вектора значением другого вектора { sz = a.sz; // размер тот же v = new int [ sz ]; // выделить память для массива for (int i = 0; i < sz; i++) //копирование элементов v [ i ] = a.v [ i ]; } В языке С++ конструктор вида T(const T&) называется конструкторомкопирования для типа T. Любую инициализацию объектов типа T он выполняет спомощью значения некоторого другого объекта типа T. Помимо явнойинициализации конструкторы вида T(const T&) используются для передачипараметров по значению и получения возвращаемого функцией значения.

Шаблоны типа

Зачем программисту может понадобиться определить такой тип, как векторцелых чисел? Как правило, ему нужен вектор из элементов, тип которыхнеизвестен создателю класса Vector. Следовательно, надо суметь определитьтип вектора так, чтобы тип элементов в этом определении участвовал какпараметр, обозначающий "реальные" типы элементов: template < class T > class Vector { // вектор элементов типа T T * v; int sz; public: Vector (int s) { if (s <= 0) error ("недопустимый для Vector размер"); v = new T [ sz = s ]; // выделить память для массива s типа T } T & operator [] (int i); int size () { return sz; } //... }; Таково определение шаблона типа. Он задает способ получения семействасходных классов. В нашем примере шаблон типа Vector показывает, как можнополучить класс вектор для заданного типа его элементов. Это описаниеотличается от обычного описания класса наличием начальной конструкцииtemplate<class T>, которая и показывает, что описывается не класс, ашаблон типа с заданным параметром-типом (здесь он используется как типэлементов). Теперь можно определять и использовать вектора разных типов: void f () { Vector < int > v1 (100); // вектор из 100 целых Vector < complex > v2 (200); // вектор из 200 // комплексных чисел v2 [ i ] = complex (v1 [ x ], v1 [ y ]); //... } Возможности, которые реализует шаблон типа, иногда называютсяпараметрическими типами или генерическими объектами. Оно сходно свозможностями, имеющимися в языках Clu и Ада. Использование шаблона типане влечет за собой каких-либо дополнительных расходов времени по сравнениюс использованием класса, в котором все типы указаны непосредственно.


Поделиться:




Поиск по сайту

©2015-2024 poisk-ru.ru
Все права принадлежать их авторам. Данный сайт не претендует на авторства, а предоставляет бесплатное использование.
Дата создания страницы: 2016-02-16 Нарушение авторских прав и Нарушение персональных данных


Поиск по сайту: