BigApple.ru » Программы » C++ » Определение класса по объекту

Определение класса по объекту

Добавлено: 22.02.2012
Автор: AlexKurochkin

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

Внедрение указателя на объект класса

Самое очевидное решение — внедрять указатель на Class в любой объект, вложенный или нет.class Object { // Предок всех реальных классовprotected:

static ObjectClass s_my_class;

Class* my_class; // == &s_my_class;public:

Object() : my_class(&s_my_class) {}

Class* My_Class() { return my_class; }};

class Foo : public Objectprotected:

static FooClass s_my_class;public:

Foo() { my_class = &s_my_class; }};

Все классы порождаются от общего предка Object, в котором определяется протокол для полученияобъекта Class. Вы имеете полное право использовать одни и те же имена членов на разных уровняхиерархии классов (как это сделано с s_my_class в нашем примере). Компилятор выбирает имя,находящееся в непосредственной области действия. Более того, конструкторы выполняются в порядке«базовый класс/переменные класса/ производные классы», поэтому последний конструктор оставитmy_class правильное значение. Эта схема позволяет всегда получить объект Class независимо оттого, сколько выполнялось преобразований типа от производных к базовым классам.

Издержки составляют четыре байта, необходимые для хранения указателя. Виртуальные функции нетребуются, поэтому нам не придется добавлять v-таблицу в класс, обходившийся без нее. Наизбыточное конструирование my_class будут потрачены дополнительные такты процессора, но длябольшинства приложений это несущественно. Пожалуй, основные издержки сводятся кдополнительному коду, находящемуся в конструкторах.

В более «чистом» варианте указатель на Class задается производящими функциями объекта Class:class Object {friend class Class;private:

Class* my_class;public:

Class* My_Class() { reutrn my_class; }};

class Class {protected:

void SetClass(Object& obj) { obj.my_class = this; }};class Foo : public Object { ... };

class FooClass : public Class {public:

Foo* make(){

Foo* f = new Foo;this->SetClass(f);return f;}};

Выглядит получше, поскольку производные от Object классы и не подозревают об этих фокусах… нотак ли это? Недостаток этого подхода — в том, что он не работает для экземпляров Foo, объявленных встеке или вложенных в другие классы в виде структур данных. Перед вами одна из ситуаций, вкоторых приходится принимать трудное решение: то ли ограничить класс только динамическимиэкземплярами, то ли искать более сложное решение и без того сложной проблемы.

Существует еще один вариант — управлять выделением памяти и хранить адеса объекта класса прямонад самим объектом в памяти вместо того, чтобы делать его переменной класса предка. Для этого нампонадобятся приемы управления памятью, описанные в части 4.

Внешние структуры данных

Как упоминалось выше, вы также можете создать глобальную коллекцию с парами экземпляр/Class.Все не так скверно, как выглядит на первый взгляд, особенно если информация Class нужна только впроцессе отладки и будет исключена в рабочем режиме. Если соблюдать осторожность в реализации,решение также распространяется и на такие вложенные объекты, как стековые переменные илиэкземпляры, хотя для этого вам понадобится соответствующая поддержка со стороны конструктора идеструктора основного класса.

Нестандартные пространства памяти

Другое решение, рассматриваемое в главах 15 и 16 — физическое разделение объектов по различнымпространствам памяти в соответствии с их классом. Оно отличается повышенной сложностью ипопросту не работает для вложенных объектов, но зато обладает впечатляющим быстродействием ималым расходом памяти.

0 комментариев
Оцените статью:
Участник обсуждения

Нажмите, чтобы ответить

     
Время формирования страницы на сервере: 0.338 сек.