Форум программистов CodeGuru
17 Январь 2018, 22:10:54 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.

Войти
Новости:
 
   Начало   Помощь Войти Регистрация  
Страниц: [1]   Вниз
  Печать  
Автор Тема: Как узнать, какого класса объект находится по указателю (C++) ?  (Прочитано 12057 раз)
0 Пользователей и 1 Гость смотрят эту тему.
Aeron
Пользователь
***
Офлайн Офлайн

Сообщений: 49


Просмотр профиля
« : 29 Май 2006, 14:06:35 »

Вобщем, в теме все сказано. Даже не знаю как точнее объяснить.
Вот, выделяю я память под несколько объектов разных классов. Потом привожу полученные указатели к указателю некоторого (одного) типа (например, void*) и все их помещаю в массив. Можно ли потом как то определить что за объект находится по конкретному указателю, или эта информация навсегда потеряна ?
Ну, есть у меня такая идея: наследовать все классы от одного, и у этого класса сделать некоторую переменную типа ID - идентификатор класса, и по нему узнавать. Но это какое то не очень красивое решение, не универсальное. Получается, для всех классов в программе надо делать один базовый. Но ведь это могут быть совершенно разные классы ! К тому же для объектов классов сторонних библиотек такого не сделать, наверно.
Как быть ? Хороший ли это подход - включать в класс информацию о самом классе ?
Записан
RIX
Интересующийся
**
Офлайн Офлайн

Сообщений: 18


Просмотр профиля
« Ответ #1 : 30 Май 2006, 08:12:55 »

Можно RTTI воспользоваться.
А своя информация о классе в самом классе это криво.
Записан
Aeron
Пользователь
***
Офлайн Офлайн

Сообщений: 49


Просмотр профиля
« Ответ #2 : 30 Май 2006, 12:27:47 »

Цитировать
Можно RTTI воспользоваться.

А не подскажете что это такое ?
Где об этом можно почитать ?

Цитировать
А своя информация о классе в самом классе это криво.

Ясно. Я и сам думал что это неудачная затея.
Записан
3V
Администратор
Ветеран
*****
Офлайн Офлайн

Сообщений: 1347



Просмотр профиля WWW
« Ответ #3 : 31 Май 2006, 22:27:23 »

Цитировать
А не подскажете что это такое ?

Run-Time Type Information
Цитировать
Где об этом можно почитать ?

В MSDN можно. Если прост набрать RTTI в индексе, то попадешь туда, куда надо.
Цитировать

Цитировать
А своя информация о классе в самом классе это криво.

Ясно. Я и сам думал что это неудачная затея.

А вот тут не совсем верно.
Классический пример - MFC.
Что там делают методы:
CObject::IsKindOf,
CRuntimeClass::IsDerivedFrom,
макрос RUNTIME_CLASS, и.т.д. ?

Но насчет RTTI - верно. Есть только одно НО(!): RTTI в реальных проектах могут и запретить использовать по каким то соображениям.
Записан

Voyager
Новичок
*
Офлайн Офлайн

Сообщений: 2


Просмотр профиля
« Ответ #4 : 22 Сентябрь 2008, 14:18:25 »

Насчёт хранения информации о классе в теле экземпляра класса. Есть мнение, что это не совсем корректно, не красиво и проч... Но дело в том, что такая информация в теле экземпляра класса уже есть! Если взять указатель на объект и уменьшить его на sizeof(void*), то в этом месте хранится указатель на таблицу виртуальных функций класса (или что-то в этом роде). В этом легко убедиться (код приводить не буду).

Заводить в объектах что-то такое, идентифицирующее класс объекта, вроде бы смысла нет: компилятор по идее и так должен знать, что за объект находится по определённому адресу. Но это только в том случае, когда вся информация об объектах известна на этапе компиляции. А если предстоит читать данные откуда-то, и в общем случае не известно, что там хранится?... Тут без какого-то идентификатора типа не обойтись.
Записан
3V
Администратор
Ветеран
*****
Офлайн Офлайн

Сообщений: 1347



Просмотр профиля WWW
« Ответ #5 : 22 Сентябрь 2008, 21:38:07 »

Насчёт хранения информации о классе в теле экземпляра класса. Есть мнение, что это не совсем корректно, не красиво и проч...
Полностью согласен. Не красиво. Но в некоторых фреймворках используется такая практика (см. пример насчет MFC выше).

Но дело в том, что такая информация в теле экземпляра класса уже есть! Если взять указатель на объект и уменьшить его на sizeof(void*), то в этом месте хранится указатель на таблицу виртуальных функций класса (или что-то в этом роде). В этом легко убедиться (код приводить не буду).
Угу.
Мало того, механизм RTTI, поддерживаемый компиляторами C++, работает только с полиморфными типами (таблица виртуальных функций быть должна).

Насчет указателя на таблицу виртуальных функций. Тут тоже есть нюанс. Дело в том, что, строго говоря, способ хранения информации о таблице виртуальных функций, а также структура самой таблицы никак не определяется стандартом C++. Т.е. в общем случае, неверно делать какие то предположения насчет этого.
Но... есть сложившаяся практика. И все, вобщем то, компиляторы делают первым членом класса указатель на vtable.
Цитата из википедии:
Цитировать
The C++ standards do not mandate exactly how dynamic dispatch must be implemented, but compilers generally use minor variations on the same basic model.

Typically, the compiler creates a separate vtable for each class. When an object is created, a pointer to this vtable, called the virtual table pointer or vpointer, is added as a hidden member of this object (often the first member). The compiler also generates "hidden" code in the constructor of each class to initialize the vpointers of its objects to the address of the corresponding vtable.
Тут про говорится "hidden member of this object (often the first member)", обратите внимание Улыбка

Но на этом предположении построена технология COM Улыбка


Заводить в объектах что-то такое, идентифицирующее класс объекта, вроде бы смысла нет: компилятор по идее и так должен знать, что за объект находится по определённому адресу. Но это только в том случае, когда вся информация об объектах известна на этапе компиляции. А если предстоит читать данные откуда-то, и в общем случае не известно, что там хранится?... Тут без какого-то идентификатора типа не обойтись.
Ну... если читать, то тут отдельный вопрос. Если данные пишутся на какой то носитель, то тут про объекты речь уже не идет. Упаковывай их в какой нибудь формат, а при чтении - разбирай.

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

З.Ы. для того, чтобы определять инфу об объекте, компиляторы и использут виртуальные функции Улыбка
З.З.Ы. и для каждого полиморфного класса, в случае, если на уровне проекта включен RTTI, генерируется статическая структура type_info.
З.З.З.Ы. а хранение своей инфы о типе в классе действительно криво. Нужно использовать стандартные средства Улыбка
Записан

c-coder
Пользователь
***
Офлайн Офлайн

Сообщений: 110


Просмотр профиля
« Ответ #6 : 23 Сентябрь 2008, 20:22:26 »

Интересный вопрос.
А с помощью RTTI можно узнавать что находиться по определенному адресу памяти ?
Например можно ли ввести адрес памяти вручную и чтобы приложение узнало какого класса объект находится по этому адресу в памяти ?
Записан
3V
Администратор
Ветеран
*****
Офлайн Офлайн

Сообщений: 1347



Просмотр профиля WWW
« Ответ #7 : 23 Сентябрь 2008, 22:14:32 »

А с помощью RTTI можно узнавать что находиться по определенному адресу памяти ?
Например можно ли ввести адрес памяти вручную и чтобы приложение узнало какого класса объект находится по этому адресу в памяти ?
В смысле - по произвольному адресу ?
В общем случае - нет.
Я же написал - RTTI работает с объектами полиморфных классов.
А если взять произвольный указатель, то он может и на не распределенную память показывать.
Если же указатель указывает на "правильный" объект, можно использовать операцию typeid.
Она возвращает константную ссылку на объект класса type_info.
Декларация класса находится в typeinfo.h и выглядит следующим образом:
Код:
class _TIDIST _rtti type_info
{

public:

tpid * tpp;

private:

cdecl type_info(const type info FAR &);

type info & cdecl operator=(const type_info _FAR &);

public:

virtual _cdecl ~type_info() ;

bool cdecl operator==(const type info FAR &) const;

bool cdecl operator!=(const type info FAR &) const;

bool _cdecl before(const type_info _FAR &) const;

const char _FAR *_cdecl name() const;

protected:

cdecl type_info(tpid * tpp) { tpp = tpp; }
};

Используя метод name, можно узнать имя класса.

Улыбка
Записан

c-coder
Пользователь
***
Офлайн Офлайн

Сообщений: 110


Просмотр профиля
« Ответ #8 : 27 Сентябрь 2008, 21:01:33 »

Получается что имя класса можно узнать только если быть уверенным что указатель указывает на объект у которого есть виртуальные функции ? Но если мы знаем это, то знаем очень много об этом указателе. Зачем тогда нам эта операция ?
Записан
michamir
Новичок
*
Офлайн Офлайн

Сообщений: 1


Просмотр профиля
« Ответ #9 : 01 Март 2011, 16:34:38 »

А помоему, "кривизну" порождает сам кастинг указателя на class до указателя void*. Мне кажется, что нет особого смысла смешивать логически несвязаные обьекты, значительно логичнее создать набор полиморфных классов и хранить указатели на базовый класс. В этом случае и "кривизны" осовой не будет, если спросить у обьекта "ты кто?", да и потребность знать точный тип обьекта, скорее всего, не воникнет.
Записан
Valery
Пользователь
***
Офлайн Офлайн

Сообщений: 83


Просмотр профиля
« Ответ #10 : 06 Март 2011, 23:28:30 »

занимаясь дизасемблированием MFC я примерно понял как работает RTTI
Цитировать
только с полиморфными типами
необходимое условие класс должен быть  производным от CObject (про что кстати и пишет MSDN)
таблица виртуальных функций выглядит так
1 GetRuntimeClass
2 virtual destructor
3 serialise

GetRuntimeClass это как раз то что и выдаст информацию о классе
хранится она не в самом классе(объекте) а в отдельной структуре
посему указатели надо приводить не к void* а к CObject*
С уважением Валерий
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.21 | SMF © 2015, Simple Machines Valid XHTML 1.0! Valid CSS!