Возможно ли по указателю типа void узнать на объект какого т
От: Phoenics Россия https://sourceforge.net/projects/phengine
Дата: 12.10.06 18:29
Оценка:
Уважаемые граждане форумчане, тут вот такя задачка подвернулась.

Дано: Есть указатель void *ptr; Известно что этот указатель указывает на реально существующий объект какого-то класса АА, так же известно что любой из классов АА является потомком класса А.

Нужно: 1. По указателю ptr узнать реальный тип объекта, привести указатель ptr к этому типу и...
2. вызвать метод класса АА, унаследованный им от класса А;

Ну второе-то вроде просто если выполнить первое

Вопрос: Возможно ли такое проделать вообще? Т.е. возможно ли по указателю типа void узнать на объект какого типа он указывает?

Зарание благодарен.
---=== С наилучшими пожеланиями, Phoenics ===---
_
Re: Возможно ли по указателю типа void узнать на объект како
От: Аноним  
Дата: 12.10.06 18:33
Оценка:
Добавить в АА виртуальный метод возвращающий некий идентификатор, перегрузить метод в потомках. Но вообще то что вам нужно — верный признак неправильного дизайна архитектуры.
PS есть еще RTTI,,,, Но — пересмотрите структуру наследования с возможностью применения виртуальных методов.
Re: Возможно ли по указателю типа void узнать на объект како
От: antidotcb Украина  
Дата: 12.10.06 18:43
Оценка: -1
Здравствуйте, Phoenics, Вы писали:

P>Уважаемые граждане форумчане, тут вот такя задачка подвернулась.


P>Дано: Есть указатель void *ptr; Известно что этот указатель указывает на реально существующий объект какого-то класса АА, так же известно что любой из классов АА является потомком класса А.


P>Нужно: 1. По указателю ptr узнать реальный тип объекта, привести указатель ptr к этому типу и...

P>2. вызвать метод класса АА, унаследованный им от класса А;

P>Ну второе-то вроде просто если выполнить первое


P>Вопрос: Возможно ли такое проделать вообще? Т.е. возможно ли по указателю типа void узнать на объект какого типа он указывает?


P>Зарание благодарен.


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

   A *a = dynamic_cast<A *>(ptr);
Re: Возможно ли по указателю типа void узнать на объект како
От: np9mi7 Россия  
Дата: 12.10.06 18:43
Оценка:
Здравствуйте, Phoenics, Вы писали:

P>Дано: Есть указатель void *ptr; Известно что этот указатель указывает на реально существующий объект какого-то класса АА, так же известно что любой из классов АА является потомком класса А.


Зачем тогда использовать void если все в одной иерархии? Использовать базовый объект и всё — все проблемы решены;

P>Нужно: 1. По указателю ptr узнать реальный тип объекта, привести указатель ptr к этому типу и...

P>2. вызвать метод класса АА, унаследованный им от класса А;

Опять, с указателем на базовый объект все получиться;

P>Вопрос: Возможно ли такое проделать вообще? Т.е. возможно ли по указателю типа void узнать на объект какого типа он указывает?


Узнать на что указывает void нельзя;

Но, наверняка все эти объекты где либо лежат — контейнер. Тогда можно запоминать тип объекта при его добавлении в контейнер;

Точно необходимо использование void? Задача смыхивает на классический полиморфизм и с его использованием все станет понятно и просто;
"В любое мгновение принятия решения, лучшее, что вы можете сделать, это принять правильное решение; следующим лучшим вариантом будет принять неправильное решение, худший вариант – не принимать решения совсем" (c) Теодор Рузвельт.
Re[2]: Возможно ли по указателю типа void узнать на объект к
От: Phoenics Россия https://sourceforge.net/projects/phengine
Дата: 12.10.06 19:50
Оценка:
A>
A>   A *a = dynamic_cast<A *>(ptr);
A>


Компилятор VC7.0 грит error C2681: 'void *' : invalid expression type for dynamic_cast

А можно ли просто привести тип к базовому? Типа A *a = (A*) pVoidPtr; Не будет ли перекосов при множественном наследовании или ещё в каких-нибудь ситуациях? Вызываемый метод не виртуальный. Наверное стоит сказать что метод который должен вызываться это перегруденный оператор delete, Ни у кого из классов потомков он не переопределяется.

P.S. Спасибо всем ответившим
---=== С наилучшими пожеланиями, Phoenics ===---
_
Re: Возможно ли по указателю типа void узнать на объект како
От: IROV..  
Дата: 12.10.06 20:24
Оценка: 1 (1)
Здравствуйте, 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 узнать на объект како
От: strcpy Россия  
Дата: 12.10.06 21:48
Оценка: :)
P>Нужно: 1. По указателю ptr узнать реальный тип объекта, привести указатель ptr к этому типу и...
Выцарапать из ptr указатель на vtbl и сравнить с известными vtbl. С кем совпадёт -- того и класс.
Удвой число ошибок, если не получается добиться цели.
Re[2]: Возможно ли по указателю типа void узнать на объект к
От: np9mi7 Россия  
Дата: 13.10.06 06:30
Оценка:
Здравствуйте, IROV.., Вы писали:

Ага, и в итоге получить такие проблемы:
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 type
class WrapperType
{
    /// declaration for delete type
    template <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 constructor
    template <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 member
    void Function (int Value)
    {
        Function_ (Value);
    }

};

class ObjectType
{
public:
    void Function (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 узнать на объект како
От: pivoo Россия  
Дата: 13.10.06 07:11
Оценка:
Здравствуйте, Phoenics, Вы писали:

P>Уважаемые граждане форумчане, тут вот такя задачка подвернулась.


P>Дано: Есть указатель void *ptr; Известно что этот указатель указывает на реально существующий объект какого-то класса АА, так же известно что любой из классов АА является потомком класса А.


P>Нужно: 1. По указателю ptr узнать реальный тип объекта, привести указатель ptr к этому типу и...

P>2. вызвать метод класса АА, унаследованный им от класса А;

P>Ну второе-то вроде просто если выполнить первое


P>Вопрос: Возможно ли такое проделать вообще? Т.е. возможно ли по указателю типа void узнать на объект какого типа он указывает?


P>Зарание благодарен.


Если первое тебе нужно только для того чтобы выполнить второе, и вызываемый метод унаселдован от А, то нужно
просто привести ptr к А* и вызвать этот метод.
Re[3]: Возможно ли по указателю типа void узнать на объект к
От: Кодт Россия  
Дата: 13.10.06 07:47
Оценка:
Здравствуйте, Phoenics, Вы писали:

A>>
A>>   A *a = dynamic_cast<A *>(ptr);
A>>


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, являющуюся обёрткой стейтмента
template<class T> void checked_delete(void* p) { delete reinterpret_cast<T*>(p); }
... << RSDN@Home 1.2.0 alpha rev. 655>>
Перекуём баги на фичи!
Re[4]: Возможно ли по указателю типа void узнать на объект к
От: np9mi7 Россия  
Дата: 13.10.06 08:15
Оценка:
Здравствуйте, Кодт, Вы писали:

К>
К>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 узнать на объект к
От: Phoenics Россия https://sourceforge.net/projects/phengine
Дата: 13.10.06 11:26
Оценка:
Здравствуйте, Кодт, Вы писали:


К>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 узнать на объект к
От: np9mi7 Россия  
Дата: 13.10.06 11:35
Оценка:
Здравствуйте, Phoenics, Вы писали:

P>У меня там целый массив этих указателей void и все они могут указывать на разные объекты казных классов. Мне нужно корректно вызвать оператор delete для них


Прочти внимательно пост http://rsdn.ru/Forum/Message.aspx?mid=2161260&amp;only=1
Автор: np9mi7
Дата: 13.10.06
, там делается всё что ты описал;

P>А вот это идея интресная. Я могу отправить туда указатель на деструктор? Получится что-то типа колбэка я так понимаю. Т.е. я мог бы хранить не только указатель на сам объект, но ещё и указатель на очищающую функцию. Затем когда надо будет удалить объект я сначала вызываю для него очищающую функцию (типа деструктора что ыб удаление прошло корректно), а затем освобождаю память из под самого объекта.


/// declaration for wrapper type
class WrapperType
{
    /// declaration for delete type
    template <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 constructor
    template <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 member
    void Function (int Value)
    {
        Function_ (Value);
    }

};
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
"В любое мгновение принятия решения, лучшее, что вы можете сделать, это принять правильное решение; следующим лучшим вариантом будет принять неправильное решение, худший вариант – не принимать решения совсем" (c) Теодор Рузвельт.
Re[5]: Возможно ли по указателю типа void узнать на объект к
От: Кодт Россия  
Дата: 13.10.06 13:04
Оценка:
Здравствуйте, 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().

Если же ты очень хочешь проводить разрушение порознь — т.е. сперва деструктор, затем отдельно освобождение памяти — то напиши две функции (или одну с параметрами что делать)
typedef void (*destruct_fun)(void*, bool, bool);

template<class T> void checked_destruct(void* pv, bool destruct, bool release)
{
    if(destruct && release)
        delete (T*)pv;
    else if(destruct)
        ((T*)pv)->~T();
    else if(release)
        T::operator delete(pv);
}
... << RSDN@Home 1.2.0 alpha rev. 655>>
Перекуём баги на фичи!
Re: Возможно ли по указателю типа void узнать на объект како
От: Phoenics Россия https://sourceforge.net/projects/phengine
Дата: 14.10.06 08:12
Оценка:
Всем большое спасибо за ответы.

Вы мне показали в какой геморой я вляпался и что чем дальше в лес, тем больше дров.
Поэтому я пришёл к выводу что лучшим решением в данной ситуации будет действительно перепроектировать ту часть программы которой этот геморой требуется. А то и доработка и поддержка всего этого кода может стать просто адской мукой.

Всем ещё раз большое спасибо.
---=== С наилучшими пожеланиями, Phoenics ===---
_
Re[5]: Возможно ли по указателю типа void узнать на объект к
От: i-maverick Россия  
Дата: 14.10.06 08:43
Оценка:
Здравствуйте, np9mi7, Вы писали:

К>>
К>>AA* pAA = dynamic_cast<AA*>(pA); // в случае неудачи получим NULL
К>>


N>Может получить и __non_rtti_object exception (тип исключения зависит от реализации);


__non_rtti_object exception выскакивает только в случае ссылочного dynamic_cast, если в проекте отключена поддержка RTTI. В варианте с указателем — null pointer по стандарту.
Re[3]: Возможно ли по указателю типа void узнать на объект к
От: IROV..  
Дата: 14.10.06 10:32
Оценка:
Здравствуйте, 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; Известно что этот указатель указывает на реально существующий объект какого-то класса АА, так же известно что любой из классов АА является потомком класса А


я не волшебник, я только учусь!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.