Модераторы: Daevaorn

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Сохранение указателя на виртуальную функцию-член 
:(
    Опции темы
MrLukS
Дата 4.8.2010, 17:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 11
Регистрация: 31.7.2009

Репутация: нет
Всего: нет



Есть класс:
Код

class SomeClass
{
public:
    virtual void SomeFunc(int SomeParam);
};


Необходимо получить указатель на SomeFunc и сохранить его в переменную. Поиск по Vtable не предлагать - в оригинальном классе огромное количество функций и он все время меняется. 

Код

DWORD dwFuncPtr = &SomeClass::SomeFunc; // Don't work
DWORD dwFuncPtr = reinterpret_cast<DWORD>&SomeClass:SomeFunc; // Don't work
// ... 


Это сообщение отредактировал(а) MrLukS - 4.8.2010, 17:35
PM MAIL   Вверх
bsa
Дата 4.8.2010, 18:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 9185
Регистрация: 6.4.2006
Где: Москва, Россия

Репутация: 63
Всего: 196



Указатель на не статический метод класса имеет размер в два раза больший, чем обычный указатель. Поэтому в DWORD он не поместится. И вообще, не делай этого. Это плохой тон программирования, ты себя жестко привязываешь к разрядности текущего процессора. Т.е. даже если ты это и сделаешь, то под 64-х битной виндой это работать не будет.
Ты лучше скажи, зачем тебе это надо, и мы посоветуем, как лучше это сделать.

Это сообщение отредактировал(а) bsa - 4.8.2010, 18:08
PM   Вверх
Cheloveck
Дата 4.8.2010, 18:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1578
Регистрация: 26.7.2008
Где: Тула

Репутация: 3
Всего: 32



Цитата(bsa @  4.8.2010,  18:07 Найти цитируемый пост)
в DWORD он не поместится


Цитата(bsa @  4.8.2010,  18:07 Найти цитируемый пост)
не делай этого


Цитата(bsa @  4.8.2010,  18:07 Найти цитируемый пост)
Это плохой тон программирования

угу. 
Делай типа так
Код

#include <iostream>

class SomeClass
{
public:
    virtual void SomeFunc(int SomeParam)
    {
        std::cout << SomeParam << std::endl;
    }
};

typedef void (SomeClass::*SomeFunctT)(int);

void Foo(SomeFunctT pointer)
{
    SomeClass sc;
    (sc.*pointer)(100);
}

int main()
{
    SomeFunctT pointer = &SomeClass::SomeFunc;
    Foo(pointer);
}





--------------------
user posted image
PM Jabber   Вверх
icecrashldr
Дата 4.8.2010, 18:12 (ссылка)    | (голосов:6) Загрузка ... Загрузка ... Быстрая цитата Цитата


Developer
*


Профиль
Группа: Участник
Сообщений: 122
Регистрация: 5.7.2010

Репутация: нет
Всего: нет



Код

void * ptrVar;
    SomeClass objSomeClass;
    void (__thiscall SomeClass::* ptrSomeFunc)(int);

    ptrSomeFunc = &SomeClass::SomeFunc;
    __asm {
        mov eax, ptrSomeFunc
        mov ptrVar, eax
    }

PM MAIL WWW   Вверх
Cheloveck
Дата 4.8.2010, 18:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1578
Регистрация: 26.7.2008
Где: Тула

Репутация: 3
Всего: 32



Самые распространённые ошибки в 64-битных системах - это попытки записать указатель в 32-битную переменную
http://habrahabr.ru/blogs/cpp/97810/

Добавлено через 53 секунды
icecrashldr, вот так одним махом похоронить переносимость? не хорошо это!


--------------------
user posted image
PM Jabber   Вверх
Abyx
Дата 4.8.2010, 18:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 601
Регистрация: 3.11.2009

Репутация: 1
Всего: 10



MrLukS, он не влезет в dword. reinterpret_cast такой каст не выполнит даже если влезет.
надо использовать union.

надо отключить множественное наследование, чтобы указатель мог влезть в dword.
Код

class __single_inheritance SomeClass


подробнее - поиск по форуму
PM MAIL   Вверх
icecrashldr
Дата 4.8.2010, 18:17 (ссылка)    | (голосов:2) Загрузка ... Загрузка ... Быстрая цитата Цитата


Developer
*


Профиль
Группа: Участник
Сообщений: 122
Регистрация: 5.7.2010

Репутация: нет
Всего: нет



Код

class SomeClass
{
public:
    virtual 
    void 
    SomeFunc(int SomeParam);

    int someField;
};

void
SomeClass::SomeFunc(int SomeParam)
{
    printf(__FUNCTION__ " value %d \n", someField);
}

int
__cdecl
main(
     int argc,
     char * argv[]
)
{
    void * ptrVar;
    SomeClass objSomeClass;
    void (__thiscall SomeClass::* ptrSomeFunc)(int);

    objSomeClass.someField= 5;

    ptrSomeFunc = &SomeClass::SomeFunc;

    __asm {
        mov eax, ptrSomeFunc
        //mov ptrVar, eax 
        lea ecx, [objSomeClass]
        push 2
        call eax
    }

return 1;
}

Вот полноценный вызов функции ... 

PM MAIL WWW   Вверх
MrLukS
Дата 4.8.2010, 18:24 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 11
Регистрация: 31.7.2009

Репутация: нет
Всего: нет



Cheloveck, код должен работать только в 32 битных системах. Кроме того, я сказал что мне нужно сохранить указатель как число, а не как непосредственно функцию.
icecrashldr, спасибо, это именно то что мне нужно... Я так и думал, что тут без задействования ассемблера не обойтись. 

Указатель нужен для перехвата функции. (MS Detours)

Это сообщение отредактировал(а) MrLukS - 4.8.2010, 18:26
PM MAIL   Вверх
Abyx
Дата 4.8.2010, 18:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 601
Регистрация: 3.11.2009

Репутация: 1
Всего: 10



MrLukS, вы свою функцию перехватываете чтоли?)

но асм там полюбому не нужен

Это сообщение отредактировал(а) Abyx - 4.8.2010, 18:30
PM MAIL   Вверх
MrLukS
Дата 4.8.2010, 18:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 11
Регистрация: 31.7.2009

Репутация: нет
Всего: нет



Abyx, я функцию из API перехватываю.  
Я промучился часов 5 пытаясь нагуглить что-нибудь, а на асме все и понятно, и работает. 
PM MAIL   Вверх
Cheloveck
Дата 4.8.2010, 18:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1578
Регистрация: 26.7.2008
Где: Тула

Репутация: 3
Всего: 32



Цитата(MrLukS @  4.8.2010,  18:24 Найти цитируемый пост)
Я так и думал, что тут без задействования ассемблера не обойтись. 

Обойтись!
Код

#include <iostream>
#include <memory>

class SomeClass
{
public:
    virtual void SomeFunc(int SomeParam)
    {
        std::cout << SomeParam << std::endl;
    }
};

typedef void (SomeClass::*SomeFunctT)(int);

struct Pointer
{
    SomeFunctT m_pointer;
    std::auto_ptr<SomeClass> mp_object;
};

void Foo(ptrdiff_t number)
{
    Pointer * p = reinterpret_cast<Pointer *>(number);
    SomeClass * obj = p->mp_object.get();
    (obj->*(p->m_pointer))(100);
}

int main()
{
    std::auto_ptr<SomeClass> obj(new SomeClass);
    SomeFunctT pf = &SomeClass::SomeFunc;
    Pointer * pointer = new Pointer;
    pointer->m_pointer = pf;
    pointer->mp_object = obj;
    ptrdiff_t number = reinterpret_cast<ptrdiff_t>(pointer);
    Foo(number);
    delete pointer;
}

http://codepad.org/ewI1DmX7

Это сообщение отредактировал(а) Cheloveck - 4.8.2010, 18:54


--------------------
user posted image
PM Jabber   Вверх
Abyx
Дата 4.8.2010, 18:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 601
Регистрация: 3.11.2009

Репутация: 1
Всего: 10



вместо __thiscall удобно использовать __fastcall
PM MAIL   Вверх
MrLukS
Дата 4.8.2010, 18:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 11
Регистрация: 31.7.2009

Репутация: нет
Всего: нет



Chelovek, слишком сложный код. Повторяю, мне не нужна переносимость, код должен работать только в 32 битной системе.
Abyx, к сожалению, мне нужен именно _thiscall. 

Немного порыл в сторону VTable:
Код

size_t** vtable = *reinterpret_cast<size_t***>(new SomeClass);

Теперь, по сути, vtable это двумерный массив указателей на виртуальные функции. Вот только почему-то там нет адреса &SomeClass::SomeFunc
PM MAIL   Вверх
Cheloveck
Дата 4.8.2010, 19:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1578
Регистрация: 26.7.2008
Где: Тула

Репутация: 3
Всего: 32



Цитата(MrLukS @  4.8.2010,  18:57 Найти цитируемый пост)
слишком сложный код.

да C++ вообще язык сложный......


--------------------
user posted image
PM Jabber   Вверх
Abyx
Дата 4.8.2010, 19:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 601
Регистрация: 3.11.2009

Репутация: 1
Всего: 10



MrLukS, опишите вашу проблему подробнее
PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.1112 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.