6.5 Реализация — Object

Предыдущая  Содержание  Следующая V*D*V

Реализация класса Object прямолинейна: конструктор и деструктор возвращают self, а differ() проверяет, являются ли указатели двух его аргументов равными. Определения этих тривиальных реализаций являются, однако, очень важными: мы используем одно дерево классов и делаем Object конечным суперклассом любого другого класса; если какой-то класс не перезаписывает какой-то метод, например differ(), он наследует его от Object, то есть каждый класс имеет по крайней мере простейшее определение для каждого динамически компонуемого метода уже применимого к Object.

Это общий принцип безопасности: всякий раз вводя новый динамически компонуемый метод, мы будем немедленно реализовывать его для этого первого класса. Таким образом мы никогда сможем попасть в ловушку, выбрав совершенно неопределённый метод. Наглядным примером является метод puto() для Object:

 

static int Object_puto (const void * _self, FILE * fp) {

    const struct Class * class = classOf(_self);

 

    return fprintf(fp, "%s at %p\n", class -> name, _self);

}

 

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

puto() полагается на функцию доступа classOf(), которая выполняет некоторые проверки безопасности и возвращает дескриптор класса объекта:

 

const void * classOf (const void * _self) {

    const struct Object * self = _self;

 

    assert(self && self -> class);

    return self -> class;

}

 

Аналогичным образом можно запросить объект о его размере (* Орфография, вероятно, будет порождать ошибки, но я просто не мог удержаться от каламбура. Изобретение хороших имён методов это искусство) — помните, что в ANSI-C технически объект является простым void *:

 

size_t sizeOf (const void * _self) {

    const struct Class * class = classOf(_self);

 

    return class -> size;

}

 

Спорно, следует ли запрашивать объект о размере, или же следует спрашивать его только о классе, а затем явно запрашивать класс о размере. Если мы реализуем sizeOf() для объектов, то не сможем применить его к описанию класса, чтобы получить соответствующий размер объекта — мы получим размер описания самого класса. Тем не менее, практика показывает, что определение sizeOf() для объектов является предпочтительным. super() наоборот является статически скомпонованным методом, который возвращает суперкласс класса, а не объекта.

 

Предыдущая  Содержание  Следующая