Программирование >>  Поддержка объектно-ориентированного программирования 

1 ... 37 38 39 [ 40 ] 41 42 43 ... 120


void f()

char stack s1(100); char stack s2(200); s1.push(a); s2.push(s1.pop()); char ch = s2.pop(); cout << ch << \n;

Когда начинает выполняться f(), вызывается конструктор char stack, который размещает массив из 100 символов s1 и массив из 200 символов s2. При возврате из f() память, которая была занята обоими массивами, будет освобождена.

5.2.6 Подстановка

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

Преодолеть эту трудность помогают функции-подстановки (inline). Если в описании класса функция-член определена, а не только описана, то она считается подстановкой. Это значит, например, что при трансляции функций, использующих char stack из предыдущего примера, не будет использоваться никаких операций вызова функций, кроме реализации операций вывода! Другими словами, при разработке такого класса не нужно принимать во внимание затраты на вызов функций. Любое, даже самое маленькое действие, можно смело определять как функцию без потери эффективности. Это замечание снимает наиболее часто приводимый довод в пользу общих членов данных.

Функцию-член можно описать со спецификацией inline и вне описания класса:

class char stack { int size; char* top; char* s; public:

char pop(); ...

inline char char stack::pop()

return *--top;

Отметим, что недопустимо описывать разные определения функции-члена, являющейся подстановкой, в различных исходных файлах ($$R.7.1.2). Это нарушило бы понятие о классе как о цельном типе.

5.3 Интерфейсы и реализации

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

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



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

5.3.1 Альтернативные реализации

Пока описание общей части класса и функций-членов остается неизменным, можно, не влияя на пользователей класса, менять его реализацию. В подтверждение этого рассмотрим таблицу имен из программы калькулятора, приведенной в главе 3. Структура ее такова:

struct name { char* string; name* next; double value;

А вот вариант класса table (таблица имен):

файл table.h class table { name* tbl; public:

table() { tbl = 0; } name* look(char*, int = 0);

name* insert(char* s) { return look(s,1); }

Эта таблица отличается от определенной в главе 3 тем, что это настоящий тип. Можно описать несколько таблиц, завести указатель на таблицу и т.д. Например:

#include table.h table globals; table keywords; table* locals;

main()

locals = new table; ...

Приведем реализацию функции table::look(), в которой используется линейный поиск в списке имен таблицы:

#include <string.h> name* table::look(char* p, int ins)

for (name* n = tbl; n; n=n->next)

if (strcmp(p,n->string) == 0) return n; if (ins == 0) error( имя не найдено ); name* nn = new name; nn->string = new char[strlen(p)+1]; strcpy(nn->string,p); nn->value = 1; nn->next = tbl;

tbl = nn;

return nn;

Теперь усовершенствуем класс table так, чтобы поиск имени шел по ключу (хэш-функции от имени), как это и было сделано в примере с калькулятором. Сделать это труднее, если соблюдать ограничение, требующее, чтобы не все программы, использующие приведенную версию класса table, надо было



изменять:

class table { name** tbl; int size; public:

table(int sz = 15);

~table();

name* look(char*, int = 0); name* insert(char* s) { return look(s,1); }

Изменения в структуре данных и конструкторе произошли потому, что для хэширования таблица должна иметь определенный размер. Задание конструктора со стандартным значением параметра гарантирует, что старые программы, в которых не использовался размер таблицы, останутся верными. Стандартные значения параметров полезны в таких случаях, когда нужно изменить класс, не влияя на программы пользователей класса. Теперь конструктор и деструктор создают и уничтожают хэшированные таблицы:

table::table(int sz)

if (sz < 0) error( размер таблицы отрицателен ); tbl = new name*[size = sz]; for ( int i = 0; i<sz; tbl[i] = 0;

table::~table()

for (int i = 0; i<size; {

name* nx;

for (name* n = tbl[i]; n; n=nx) { nx = n->next; delete n->string; delete n;

delete tbl;

Описав деструктор для класса name, можно получить более ясный и простой вариант table::~table(). Функция поиска практически совпадает с приведенной в примере калькулятора ($$3.1 3):

name* table::look(const char* p, int ins)

int ii = 0; char* pp = p;

while (*pp) ii = ii<<1 *pp++; if (ii < 0) ii = -ii; ii %= size;

for (name* n=tbl[ii]; n; n=n->next)

if (strcmp(p,n->string) == 0) return n; name* nn = new name; nn->string = new char[strlen(p)+1]; strcpy(nn->string,p); nn->value = 1; nn->next = tbl[ii]; tbl[ii] = nn; return nn;

Очевидно, что функции-члены класса должны перетранслироваться всякий раз, когда в описание класса вносится какое-либо изменение. В идеале такое изменение никак не должно отражаться на



1 ... 37 38 39 [ 40 ] 41 42 43 ... 120

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика