Уважаемые граждане форумчане, тут вот такя задачка подвернулась.
Дано: Есть указатель void *ptr; Известно что этот указатель указывает на реально существующий объект какого-то класса АА, так же известно что любой из классов АА является потомком класса А.
Нужно: 1. По указателю ptr узнать реальный тип объекта, привести указатель ptr к этому типу и...
2. вызвать метод класса АА, унаследованный им от класса А;
Ну второе-то вроде просто если выполнить первое
Вопрос: Возможно ли такое проделать вообще? Т.е. возможно ли по указателю типа void узнать на объект какого типа он указывает?
Зарание благодарен.
---=== С наилучшими пожеланиями, Phoenics ===--- _
Re: Возможно ли по указателю типа void узнать на объект како
От:
Аноним
Дата:
12.10.06 18:33
Оценка:
Добавить в АА виртуальный метод возвращающий некий идентификатор, перегрузить метод в потомках. Но вообще то что вам нужно — верный признак неправильного дизайна архитектуры.
PS есть еще RTTI,,,, Но — пересмотрите структуру наследования с возможностью применения виртуальных методов.
Re: Возможно ли по указателю типа void узнать на объект како
Здравствуйте, Phoenics, Вы писали:
P>Уважаемые граждане форумчане, тут вот такя задачка подвернулась.
P>Дано: Есть указатель void *ptr; Известно что этот указатель указывает на реально существующий объект какого-то класса АА, так же известно что любой из классов АА является потомком класса А.
P>Нужно: 1. По указателю ptr узнать реальный тип объекта, привести указатель ptr к этому типу и... P>2. вызвать метод класса АА, унаследованный им от класса А;
P>Ну второе-то вроде просто если выполнить первое
P>Вопрос: Возможно ли такое проделать вообще? Т.е. возможно ли по указателю типа void узнать на объект какого типа он указывает?
P>Зарание благодарен.
ну если ты уверен что по этому указателю всегда будет потомок или экземляр класса А, то добавь функцию в класс А, который будет возвращать тип объекта, и переопределяй её во всех потомках. по мойму проще пареной репы. второе следует из первого, а вообще если уверен что там указатель на потомок или экземпляр класса а , то сразу делай так
A *a = dynamic_cast<A *>(ptr);
Re: Возможно ли по указателю типа void узнать на объект како
Здравствуйте, Phoenics, Вы писали:
P>Дано: Есть указатель void *ptr; Известно что этот указатель указывает на реально существующий объект какого-то класса АА, так же известно что любой из классов АА является потомком класса А.
Зачем тогда использовать void если все в одной иерархии? Использовать базовый объект и всё — все проблемы решены;
P>Нужно: 1. По указателю ptr узнать реальный тип объекта, привести указатель ptr к этому типу и... P>2. вызвать метод класса АА, унаследованный им от класса А;
Опять, с указателем на базовый объект все получиться;
P>Вопрос: Возможно ли такое проделать вообще? Т.е. возможно ли по указателю типа void узнать на объект какого типа он указывает?
Узнать на что указывает void нельзя;
Но, наверняка все эти объекты где либо лежат — контейнер. Тогда можно запоминать тип объекта при его добавлении в контейнер;
Точно необходимо использование void? Задача смыхивает на классический полиморфизм и с его использованием все станет понятно и просто;
"В любое мгновение принятия решения, лучшее, что вы можете сделать, это принять правильное решение; следующим лучшим вариантом будет принять неправильное решение, худший вариант – не принимать решения совсем" (c) Теодор Рузвельт.
Re[2]: Возможно ли по указателю типа void узнать на объект к
Компилятор VC7.0 грит error C2681: 'void *' : invalid expression type for dynamic_cast
А можно ли просто привести тип к базовому? Типа A *a = (A*) pVoidPtr; Не будет ли перекосов при множественном наследовании или ещё в каких-нибудь ситуациях? Вызываемый метод не виртуальный. Наверное стоит сказать что метод который должен вызываться это перегруденный оператор delete, Ни у кого из классов потомков он не переопределяется.
P.S. Спасибо всем ответившим
---=== С наилучшими пожеланиями, Phoenics ===--- _
Re: Возможно ли по указателю типа void узнать на объект како
Здравствуйте, Phoenics, Вы писали:
P>Уважаемые граждане форумчане, тут вот такя задачка подвернулась.
P>Дано: Есть указатель void *ptr; Известно что этот указатель указывает на реально существующий объект какого-то класса АА, так же известно что любой из классов АА является потомком класса А.
P>Нужно: 1. По указателю ptr узнать реальный тип объекта, привести указатель ptr к этому типу и... P>2. вызвать метод класса АА, унаследованный им от класса А;
A *a = static_cast<A*>(ptr);
AA *aa = dynamic_cast<AA*>(a);
if( aa )
{
aa->method();
}
я не волшебник, я только учусь!
Re: Возможно ли по указателю типа void узнать на объект како
P>Нужно: 1. По указателю ptr узнать реальный тип объекта, привести указатель ptr к этому типу и...
Выцарапать из ptr указатель на vtbl и сравнить с известными vtbl. С кем совпадёт -- того и класс.
Удвой число ошибок, если не получается добиться цели.
Re[2]: Возможно ли по указателю типа void узнать на объект к
class BaseType
{
public:
virtual void Function () {}
virtual ~BaseType () {}
};
class ChildType : public BaseType
{
public:
virtual void Function () {}
virtual ~ChildType () {}
};
int main ()
{
int Value;
void * Pointer ( & Value);
BaseType * Base (static_cast <BaseType * const>
(Pointer));
ChildType * Child (dynamic_cast <ChildType * const>
(Base)); /// тут всё упалоreturn 0;
}
, с учетом того что вызывающий код работает только с void * и может получить не то что нужно;
Если так хочеться использовать именно void * (который создан в С++ что бы работать с не инициализированной памятью), а не полиморфизм (нормальная практика) то можно сделать что то вроде:
#include <vector> /// for example only#include <boost/bind.hpp> /// use in declaration for wrapper type#include <boost/function.hpp> /// use in declaration for wrapper type
/// declaration for wrapper typeclass WrapperType
{
/// declaration for delete typetemplate <typename ValueType>
struct DeleteType
{
static void Delete (void * Pointer)
{
delete static_cast <ValueType * const>
(Pointer);
}
};
/// declaration for delete member
boost::function0 <void> Delete_;
/// declaration for function member
boost::function1 <void, int> Function_;
public:
/// declaration for wrapper constructortemplate <typename ValueType> explicit WrapperType
(ValueType * Value) : Delete_ (boost::bind (DeleteType
<ValueType>::Delete, Value)), Function_ (boost::bind
( & ValueType::Function, Value, _1)) {}
/// declaration for wrapper destructor
~WrapperType ()
{
Delete_ ();
}
/// declaration for function membervoidFunction (int Value)
{
Function_ (Value);
}
};
class ObjectType
{
public:
voidFunction (int i)
{
++ i; /// делаем соотв. обработку
}
};
int main ()
{
ObjectType * const Object
(new ObjectType ()); /// создаем объект (тип объекта известен)
WrapperType Wrapper (Object); /// создаем обложку вокруг объекта (тип объекта известен)
std::vector <WrapperType> Vector;
Vector.push_back (Wrapper); /// добавляем объект в контейнер (тип объекта не известен)
Vector.back ().Function (45); /// делаем вызов необходимой функции (тип объекта не известен)return 0;
}
, тогда и наследование не нужно + безопасность типов (правда придеться следить за сигнатурой функций — выделено);
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
"В любое мгновение принятия решения, лучшее, что вы можете сделать, это принять правильное решение; следующим лучшим вариантом будет принять неправильное решение, худший вариант – не принимать решения совсем" (c) Теодор Рузвельт.
Re: Возможно ли по указателю типа void узнать на объект како
Здравствуйте, Phoenics, Вы писали:
P>Уважаемые граждане форумчане, тут вот такя задачка подвернулась.
P>Дано: Есть указатель void *ptr; Известно что этот указатель указывает на реально существующий объект какого-то класса АА, так же известно что любой из классов АА является потомком класса А.
P>Нужно: 1. По указателю ptr узнать реальный тип объекта, привести указатель ptr к этому типу и... P>2. вызвать метод класса АА, унаследованный им от класса А;
P>Ну второе-то вроде просто если выполнить первое
P>Вопрос: Возможно ли такое проделать вообще? Т.е. возможно ли по указателю типа void узнать на объект какого типа он указывает?
P>Зарание благодарен.
Если первое тебе нужно только для того чтобы выполнить второе, и вызываемый метод унаселдован от А, то нужно
просто привести ptr к А* и вызвать этот метод.
Re[3]: Возможно ли по указателю типа void узнать на объект к
P>Компилятор VC7.0 грит error C2681: 'void *' : invalid expression type for dynamic_cast
Естественно.
Если ты уверен, что ptr — точно на A (и, возможно, на его потомков), то
A* pA = reinterpret_cast<A*>(pVoid); // первое допущение мы вынуждены сделать на свой страх и риск
AA* pAA = dynamic_cast<AA*>(pA); // в случае неудачи получим NULL
P>А можно ли просто привести тип к базовому? Типа A *a = (A*) pVoidPtr; Не будет ли перекосов при множественном наследовании или ещё в каких-нибудь ситуациях? Вызываемый метод не виртуальный. Наверное стоит сказать что метод который должен вызываться это перегруденный оператор delete, Ни у кого из классов потомков он не переопределяется.
Тогда, опять же в допущении, что это A*, просто
delete reinterpret_cast<A*>(pVoid);
Но может быть, тебе нужно косвенное удаление — подобно тому, как это делает shared_ptr, запоминающий функцию-убийцу вместе с переданным указателем?
typedef void(*deleter_func)(void*);
struct deleteable_ptr
{
void* ptr;
deleter_func del;
// всякий обвес - конструкторы, операторы и т.п. - напиши сам по вкусу
};
////////////////////////////////
deleteable_ptr p;
p.ptr = new AA();
p.del = boost::checked_delete<AA>;
/////////////////////////////////
p.del(p.ptr);
Я надеюсь, что ты знаешь разницу между стейтментом delete (совершающим вызов деструктора, затем вызов оператора) и оператором delete (просто утилизирующим память).
Поэтому del запоминает именно checked_delete, являющуюся обёрткой стейтмента
К>AA* pAA = dynamic_cast<AA*>(pA); // в случае неудачи получим NULL
К>
Может получить и __non_rtti_object exception (тип исключения зависит от реализации);
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
"В любое мгновение принятия решения, лучшее, что вы можете сделать, это принять правильное решение; следующим лучшим вариантом будет принять неправильное решение, худший вариант – не принимать решения совсем" (c) Теодор Рузвельт.
Re: Возможно ли по указателю типа void узнать на объект како
От:
Аноним
Дата:
13.10.06 09:03
Оценка:
P>Дано: Есть указатель void *ptr; Известно что этот указатель указывает на реально существующий объект какого-то класса АА, так же известно что любой из классов АА является потомком класса А.
P>Нужно: 1. По указателю ptr узнать реальный тип объекта, привести указатель ptr к этому типу и... P>2. вызвать метод класса АА, унаследованный им от класса А;
P>Ну второе-то вроде просто если выполнить первое
P>Вопрос: Возможно ли такое проделать вообще? Т.е. возможно ли по указателю типа void узнать на объект какого типа он указывает?
IMHO, в общем случае невозможно.
Даже если известно, что ptr указывает на класс-потомок от A делать
reinterpret_cast<A*>(ptr) или static_cast<A*>(ptr) нельзя,
потому что компилятору недостаточно информации для корректного приведения между типами — из-за того, что ptr объявлен как void *.
Re[4]: Возможно ли по указателю типа void узнать на объект к
К>AA* pAA = dynamic_cast<AA*>(pA); // в случае неудачи получим NULL
Чё-то я стормозил. Я же не могу написать AA* pAA = dynamic_cast<AA*>(pA); потому что не знаю конкретный тип АА. У меня там целый массив этих указателей void и все они могут указывать на разные объекты казных классов. Мне нужно корректно вызвать оператор delete для них (этот оператор предоставляется классам А) и что бы этот delete ещё и вызвал правильный деструктор для АА
К>typedef void(*deleter_func)(void*);
А вот это идея интресная. Я могу отправить туда указатель на деструктор? Получится что-то типа колбэка я так понимаю. Т.е. я мог бы хранить не только указатель на сам объект, но ещё и указатель на очищающую функцию. Затем когда надо будет удалить объект я сначала вызываю для него очищающую функцию (типа деструктора что ыб удаление прошло корректно), а затем освобождаю память из под самого объекта.
Как думаете такой вариант прокатит?
---=== С наилучшими пожеланиями, Phoenics ===--- _
Re[5]: Возможно ли по указателю типа void узнать на объект к
Здравствуйте, Phoenics, Вы писали:
P>У меня там целый массив этих указателей void и все они могут указывать на разные объекты казных классов. Мне нужно корректно вызвать оператор delete для них
, там делается всё что ты описал;
P>А вот это идея интресная. Я могу отправить туда указатель на деструктор? Получится что-то типа колбэка я так понимаю. Т.е. я мог бы хранить не только указатель на сам объект, но ещё и указатель на очищающую функцию. Затем когда надо будет удалить объект я сначала вызываю для него очищающую функцию (типа деструктора что ыб удаление прошло корректно), а затем освобождаю память из под самого объекта.
/// declaration for wrapper typeclass WrapperType
{
/// declaration for delete typetemplate <typename ValueType>
struct DeleteType
{
static void Delete (void * Pointer) /// очищающая функция
{
delete static_cast <ValueType * const>
(Pointer);
}
};
/// declaration for delete member
boost::function0 <void> Delete_; /// указатель на очищающую функцию
/// declaration for function member
boost::function1 <void, int> Function_; /// интерфейс объектовpublic:
/// declaration for wrapper constructortemplate <typename ValueType> explicit WrapperType
(ValueType * Value) : Delete_ (boost::bind (DeleteType
<ValueType>::Delete, Value)), Function_ (boost::bind
( & ValueType::Function, Value, _1)) {}
/// declaration for wrapper destructor
~WrapperType ()
{
Delete_ (); /// я сначала вызываю для него очищающую функцию
/// (типа деструктора что ыб удаление прошло корректно),
/// а затем освобождаю память из под самого объекта
}
/// declaration for function membervoid Function (int Value)
{
Function_ (Value);
}
};
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
"В любое мгновение принятия решения, лучшее, что вы можете сделать, это принять правильное решение; следующим лучшим вариантом будет принять неправильное решение, худший вариант – не принимать решения совсем" (c) Теодор Рузвельт.
Re[5]: Возможно ли по указателю типа void узнать на объект к
Здравствуйте, Phoenics, Вы писали:
К>>AA* pAA = dynamic_cast<AA*>(pA); // в случае неудачи получим NULL
P>Чё-то я стормозил. Я же не могу написать AA* pAA = dynamic_cast<AA*>(pA); потому что не знаю конкретный тип АА. У меня там целый массив этих указателей void и все они могут указывать на разные объекты казных классов. Мне нужно корректно вызвать оператор delete для них (этот оператор предоставляется классам А) и что бы этот delete ещё и вызвал правильный деструктор для АА
Сделай у класса A виртуальный деструктор. А раз они все наследуют оператор A::delete, то delete pA полностью решит твою проблему, даже без узнавания о типе.
К>>typedef void(*deleter_func)(void*);
P>А вот это идея интресная. Я могу отправить туда указатель на деструктор? Получится что-то типа колбэка я так понимаю. Т.е. я мог бы хранить не только указатель на сам объект, но ещё и указатель на очищающую функцию. Затем когда надо будет удалить объект я сначала вызываю для него очищающую функцию (типа деструктора что ыб удаление прошло корректно), а затем освобождаю память из под самого объекта.
Не надо нагромождать. checked_delete<AA> и деструктор правильный вызовет, и оператор. Точнее, она выполнит стейтмент delete с типом AA, что и приведёт к нужному деструктору AA::~AA() и оператору AA::delete(), унаследованному от A. Причём в этом случае необязательно наличие виртуального деструктора A::~A().
Если же ты очень хочешь проводить разрушение порознь — т.е. сперва деструктор, затем отдельно освобождение памяти — то напиши две функции (или одну с параметрами что делать)
Вы мне показали в какой геморой я вляпался и что чем дальше в лес, тем больше дров.
Поэтому я пришёл к выводу что лучшим решением в данной ситуации будет действительно перепроектировать ту часть программы которой этот геморой требуется. А то и доработка и поддержка всего этого кода может стать просто адской мукой.
Всем ещё раз большое спасибо.
---=== С наилучшими пожеланиями, Phoenics ===--- _
Re[5]: Возможно ли по указателю типа void узнать на объект к
К>>AA* pAA = dynamic_cast<AA*>(pA); // в случае неудачи получим NULL
К>>
N>Может получить и __non_rtti_object exception (тип исключения зависит от реализации);
__non_rtti_object exception выскакивает только в случае ссылочного dynamic_cast, если в проекте отключена поддержка RTTI. В варианте с указателем — null pointer по стандарту.
Re[3]: Возможно ли по указателю типа void узнать на объект к
Здравствуйте, np9mi7, Вы писали:
N>int main () N>{ N> N> int Value;
N> void * Pointer ( & Value);
N> BaseType * Base (static_cast <BaseType * const> N> (Pointer));
N> ChildType * Child (dynamic_cast <ChildType * const> N> (Base)); /// тут всё упало
N> return 0; N>} N>[/ccode]
Дано: Есть указатель void *ptr; Известно что этот указатель указывает на реально существующий объект какого-то класса АА, так же известно что любой из классов АА является потомком класса А