Литмир - Электронная Библиотека
A
A

v[4]==4.4

Данный вариант класса

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

17.7. Указатели на объекты класса

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

vector
точно так же, как и указатели на переменные типа
char
.

vector* f(int s)

{

  vector* p = new vector(s); // размещаем вектор в свободной

                             // памяти заполняем *p

  return p;

}

void ff()

{

  vector* q = f(4);

                  // используем *q

 delete q;        // удаляем вектор из свободной памяти

}

Обратите внимание на то, что, когда мы удаляем объект класса

vector
с помощью оператора
delete
, вызывается его деструктор. Рассмотрим пример.

vector* p = new vector(s); // размещаем вектор в свободной памяти

delete p;                  // удаляем вектор из свободной памяти

При создании объекта класса

vector
в свободной памяти оператор new выполняет следующие действия:

• сначала выделяет память для объекта класса

vector
;

• затем вызывает конструктор класса

vector
, чтобы инициализировать его объект; этот конструктор выделяет память для элементов объекта класса
vector
и инициализирует их.

Удаляя объект класса

vector
, оператор
delete
выполняет следующие действия:

• сначала вызывает деструктор класса

vector
; этот деструктор, в свою очередь, вызывает деструктор элементов (если они есть), а затем освобождает память, занимаемую элементами вектора;

• затем освобождает память, занятую объектом класса

vector
.

Обратите внимание на то, как хорошо, что эти операторы работают рекурсивно (см. раздел. 8.5.8). Используя реальный (стандартный) класс

vector
, мы можем выполнить следующий код:

vector< vector<double> >* p = new vector<vector<double> > (10);

delete p;

Здесь инструкция

delete p
вызывает деструктор класса
vector<vector<double>>
, а он, в свою очередь, вызывает деструктор элементов класса
vector<double>
, и весь вектор аккуратно освобождается, ни один объект не остается не уничтоженным, и утечка памяти не возникает.

Поскольку оператор

delete
вызывает деструкторы (для типов, в которых они предусмотрены, например, таких, как
vector
), часто говорят, что он уничтожает (destroy) объекты, а не удаляет из памяти (deallocate).

 

Программирование. Принципы и практика использования C++ Исправленное издание - _003.png
 Как всегда, следует помнить, что “голый” оператор new за пределами конструктора таит в себе опасность забыть об операторе
delete
. Если у вас нет хорошей стратегии удаления объектов (хотя она действительно проста, см., например, класс
Vector_ref
из разделов 13.10 и Д.4), попробуйте включить операторы
new
в конструкторы, а операторы
delete
— в деструкторы.

Итак, все бы ничего, но как же нам получить доступ к членам вектора, используя только указатель? Обратите внимание на то, что все классы поддерживают доступ к своим членам с помощью оператора

.
(точка), примененного к имени объекта.

vector v(4);

int x = v.size();

double d = v.get(3);

Аналогично все классы поддерживают работу оператора

–>
(стрелка) для доступа к своим членам с помощью указателя на объект.

vector* p = new vector(4);

int x = p–>size();

double d = p–>get(3);

Как и операторы

.
(точка), оператор
–>
(стрелка) можно использовать для доступа к данным-членам и функциям-членам. Поскольку встроенные типы, такие как
int
и
double
, не имеют членов, то оператор
–>
к ним не применяется. Операторы “точка” и “стрелка” часто называют операторами доступа к членам класса (member access operators).

17.8. Путаница с типами: void* и операторы приведения типов

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

*
и
[]
) непосредственно отображаются в машинные инструкции. На этом уровне язык предоставляет программисту мало удобств и возможностей, предусматриваемых системой типов. Однако иногда приходится от них отказываться, даже несмотря на меньшую степень защиты от ошибок.

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

230
{"b":"847443","o":1}