12.4 Загрузка объектов — retrieve() |
Предыдущая Содержание Следующая |
Кто читает имя класса, выделяет память объекту и вызывает geto(), чтобы заполнить его? Возможно странно, что это выполняется функцией retrieve(), которая декларируется в файле описания класса Object.d, но которая не является методом:
void * retrieve (FILE * fp); // object from file
retrieve() читает имя класса из потока как строку; каким-нибудь образом находит подходящий указатель описания класса; использует allocate(), чтобы выделить место для объекта; и просит geto() заполнить его. Поскольку заключительный указатель описания класса вставляет allocate(), geto() может в самом деле быть применён к выделенной области памяти:
struct classList { const char * name; const void * class; };
void * retrieve (FILE * fp) { char buf [BUFSIZ]; static struct classList * cL; // локальная копия static int cD = -1; // количество классов
if (cD < 0) ... build classList in cL[0..cD-1] ... if (! cD) fputs("no classes known\n", stderr);
else if (fp && ! feof(fp) && fscanf(fp, "%s", buf) == 1) { struct classList key, * p;
key.name = buf; if (p = bsearch(& key, cL, cD, sizeof key, (int (*) (const void *, const void *)) cmp)) return geto(allocate(p -> class), fp); fprintf(stderr, "%s: cannot retrieve\n", buf); } return 0; }
retrieve() требуется список имён классов и указателей описаний классов. Описания классов указывают на методы и селекторы, то есть этот список действительно гарантирует, что retrieve() использует код классов, связанный с использованием программы. Если данные для объекта считаны, методы для объекта доступны в программе — geto() только один из них. Откуда берётся список классов? Можно было бы создать его вручную, но в главе 9 мы видели munch, простую программу awk для извлечения имён классов из списка объектных модулей, создаваемого nm. Поскольку nm может быть применена к библиотеке объектных модулей, можно даже извлечь список классов, поддерживаемый всей библиотекой. Результатом является массив classes[] со списком указателей на функции инициализации класса, отсортированный по именам классов в алфавитном порядке. retrieve() могла бы искать в этом списке, вызывая каждую функцию, чтобы получить инициализированное описание класса и применяя nameOf() к результату для получения строкового представления имени класса. Это не очень эффективно, если надо получить много объектов. Поэтому retrieve() создаёт собственный список следующим образом:
extern const void * (* classes[]) (void); // munch
if (cD < 0) { for (cD = 0; classes[cD]; ++ cD) ; // подсчёт классов if (cD > 0) { // собираем имена/описания cL = malloc(cD * sizeof(struct classList)); assert(cL); for (cD = 0; classes[cD]; ++ cD) cL[cD].class = classes[cD](), cL[cD].name = nameOf(cL[cD].class); } }
У собственного списка классов есть дополнительное преимущество, он позволяет избежать дальнейших вызовов функций инициализаций классов.
|
Предыдущая Содержание Следующая |