Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.81/78: Рейтинг темы: голосов - 78, средняя оценка - 4.81
40 / 38 / 5
Регистрация: 22.01.2011
Сообщений: 670

Передача указателя на метод в функцию

06.05.2011, 22:33. Показов 16627. Ответов 3
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Подскажите плиз. Есть некий класс и в нём метод:
C++
1
2
3
4
5
6
7
8
9
10
11
...
    DWORD WINAPI func(LPVOID lParam)
    {
    ...
    return 1;
    }
 
    metod()
    {
      if(...) { MyThread=CreateThread(NULL,0,func,NULL,0,0); }
    }
выдаёт ошибку:
'CreateThread' : cannot convert parameter 3 from 'unsigned long (void *)' to 'unsigned long (__stdcall *)(void *)'
Как надо исправить?

Добавлено через 18 минут
так почему-то нормально работет, если без классов
C++
1
2
3
4
5
6
7
8
9
10
11
DWORD WINAPI WaitingFor(LPVOID lParam)
{
    return 1;
}
 
int main()
{
    HANDLE MyThread;
    MyThread=CreateThread(NULL,0,WaitingFor,NULL,0,0);//запускаем в потоке нужную нам функцию
   return 0;
}
Добавлено через 32 минуты
ну же
0
Лучшие ответы (1)
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
06.05.2011, 22:33
Ответы с готовыми решениями:

Как сделать функцию от указателя на класс и указателя на метод?
Не получается сделать функцию, параметрами которой являются указатель на класс и на метод. Обращаться к классу нужно именно по указателю,...

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

Передача в метод указателя на класс
Здравствуйте. Столкнулся со следующей проблемой: при передачи в метод пустого указателя на класс, создаю экземпляр данного класса, и...

3
Эксперт С++
 Аватар для CyBOSSeR
2348 / 1721 / 149
Регистрация: 06.03.2009
Сообщений: 3,675
06.05.2011, 22:39
dimon1984, потому что методы (функции-члены) по факту принимает на один аргумент больше чем указано в списке аргументов - указатель на объект для которого вызывается метод. Получается Вы в функцию ожидающую указатель на функцию принимающую один аргумент передаете указатель на функцию принимающую два аргумента (this и lParam). Самое простое сделать метод статическим и тогда проблема решится.
2
Эксперт С++
1069 / 848 / 60
Регистрация: 30.04.2011
Сообщений: 1,659
06.05.2011, 22:57
Лучший ответ Сообщение было отмечено как решение

Решение

Вот ликбез по обоим видам указателей:

Дело в том, что указатель на метод существенно отличается по типу от обычного указателя на функцию, даже если прототипы функции и метода внешне идентичны. Вспомним, как определяется указатель на функцию:
Code
1
тип (*имя-указателя)(список параметров);
Для сокращения записи применяют обычно оператор typedef. Следующее объявление вводит новое имя типа:
Code
1
typedef тип (*тип-указателя)(список параметров);
После этого указатель на функцию можно объявлять так:
тип-указателя имя-указателя;

Указателю присваивается адрес функции. В С++ разрешается присваивать адрес функции явно или неявно задавая операцию получения адреса:
имя-указателя = &имя-функции;
имя-указателя = имя-функции;
В последнем случае имя функции неявно преобразуется в адрес.

Вызов функции через указатель выполняется так:
Code
1
(*имя-указателя)(аргументы);
Тот же вызов можно написать в более простой форме:
имя-указателя(аргументы);

Рассмотрим несколько простых примеров. Допустим, у нас объявлен указатель на функцию:
Code
1
int (*pf)(void);
Этому указателю можно присвоить адрес любой функции с таким же прототипом, в том числе и библиотечной. Например, такой прототип имеет функция-генератор случайного числа rand(), который объявлен в заголовке библиотеки <cstdlib>:
C++
1
2
3
4
5
int f1(void) { return 1; } 
int f2(void) { return 2; }
pf = f1;    cout << pf() << endl;                // вызов f1()
pf = f2;    cout << pf() << endl;                // вызов f2()
pf = &rand; cout << pf() << endl;                // вызов rand()
Напишем теперь простой класс
C++
1
2
3
4
5
6
class Constant
{    int value;
   public: 
    Constant(const int &a): value(a) {}
    int get(void) { return value; }
};
Метод get() с виду имеет тот же прототип, что и функции в приведенном ранее фрагменте. Однако попытки присвоить адрес метода get() указателю pf компилятор пресекает «на корню». Да и не совсем понятно, как этот адрес задавать. Вариантов два.
1. Объявить объект и взять адрес метода в объекте:
C++
1
Constant A(5); pf = &A.get();
2. Не объявлять объект, а приписать префикс класса:
C++
1
pf = &Constant::get;
Первый вариант вообще неверный: и Visual C++.NET 2003, и Borland C++ Builder 6 сообщают, что операцию взятия адреса & так использовать нельзя. Второй вариант — ближе к истине: оба компилятора сообщают только о невозможности выполнить преобразование типов. Попытки прописать преобразование явно не проходят:
C++
1
2
3
pf = static_cast<int (*)(void)>(&Constant::get);
pf = reinterpret_cast<int (*)(void)>(&Constant::get); 
pf = (int (*)(void))(&Constant::get);
Все эти варианты вызывают ту же ошибку компиляции — невозможность преобразования типов. Таким образом, тип указателя на метод класса кардинально отличается от типа указателя на функцию: адрес метода нельзя присвоить указателю на функцию, даже если внешне их прототипы совпадают. Это становится понятным, если мы вспомнить, что нестатические методы получают дополнительный параметр — указатель this.
Аналогично, нельзя присвоить обычному указателю на функцию адрес виртуального метода — в этом случае дело усугубляется еще наличием в составе объекта указателя на таблицу виртуальных методов. А вот со статическими методами картина другая! Статический метод не получает никаких «лишних параметров», поэтому его адрес можно присваивать обычному указателю на функцию без всяких преобразований. Добавим в класс Constant статическое поле и статический метод с нужным нам прототипом:
C++
1
2
3
4
5
6
7
8
class Constant
{    int value;
    static int d;
public: 
    Constant(const int &a): value(a) {}
    int get(void) { return value; }
    static int getd(void) { return d; }                // статический метод
};
Тогда нашему указателю pf можно присвоить адрес статического метода согласно второму из приведенных ранее вариантов, например:
C++
1
pf = Constant::getd;        // или pf = &Constant::getd;
Префикс, естественно, необходимо писать.
Указатель на метод объявляется по-другому (см. п.п. 8.3.3 в [1]) — нужно задать имя класса в качестве префикса:
C++
1
int (Constant::*pm)(void);
Такому указателю можно присваивать адреса обычных и виртуальных методов согласно второму из приведенных ранее вариантов, например:
C++
1
pm = &Constant::get;        // или pm = Constant::get;
Адрес статического метода, так же как и адрес обычной функции, такому указателю присвоить нельзя — возникает ошибка трансляции: компилятор сообщает о невозможности выполнить преобразование типов.
И косвенный вызов метода выполняется по-другому — с помощью операции выбора члена класса .* или ->* (см. п. 5.5 в [1]). Несмотря на то, что указатель на член класса является отдельной независимой от класса переменной, вызов метода по указателю возможен только при наличии объекта, например:
C++
1
2
Constant A(5);
cout << (A.*pm)() << endl;
Выражение(A.*pm)() означает следующее: для объекта A вызвать метод, чей адрес записан в указателе pm. Слева от операции .* — объект, справа — указатель на метод. Скобки вокруг выражения A.*pm писать обязательно, так как приоритет операции вызова функции (()) выше, чем приоритет операции выбора члена класса (.*).
В выражении (объект.*указатель) можно заменить часть объект. записью указатель->, например:
C++
1
2
Constant *pc = new Constant(7);
cout << (pc->*pm)() << endl;
Обратите внимание: в выражении (pc->*pm) слева — обычный указатель на динамический объект, а справа — указатель на метод этого объекта. Это два совершенно разных типа указателя.
Интересно, что в Visual C++.NET 2003 размер sizeof(pf) указателя на функцию совпадает с размером sizeof(pm) указателя на член класса и равен 4 байта. А вот система Borland C++ Builder 6 выдает совершенно разные цифры: размер указателя на функцию равен 4 байта, а размер указателя на метод — 12 байт!
8
40 / 38 / 5
Регистрация: 22.01.2011
Сообщений: 670
07.05.2011, 00:09  [ТС]
дополню. Нашёл полезный пример:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
typedef unsigned (__stdcall *PTHREAD)(void*); 
 class CMyClass 
 { 
 public: 
 DWORD WINAPI _tMyClassMethodThread(PVOID pvContext); 
 friend DWORD WINAPI _tInnerThread(PVOID pvContext); 
 void Start(); 
 }; 
  
 //Realization 
 DWORD WINAPI _tInnerThread(PVOID pvContext) 
 { 
 CMyClass* pClass = static_cast<CMyClass*>(pvContext); 
 return(pClass->_tMyClassMethodThread(pvContext)); 
 } 
  
 DWORD WINAPI CMyClass::_tMyClassMethodThread(PVOID pvContext) 
 { 
 //... 
 } 
  
 void CMyClass::Start() 
 { 
 //... 
 HANDLE hThread = (HANDLE)_beginthreadex(...,(PTHREAD)_tInnerThread,this,...); 
 //... 
 }
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
07.05.2011, 00:09
Помогаю со студенческими работами здесь

Передача указателя на файл в метод
Доброго вечера всем. Такая проблема: C++ Builder ругается на строку в описании класса, пример под катом class OwnThing { char...

Передача в функцию указателя
Почему плохо передавать в функцию указатель на строку или массив и возвращать указатель на строку или массив?

Передача указателя в функцию
Поиском не пользовался, возможно данный вопрос уже проскакивал. Проблема том, что VS2010 на отрез отказывается передавать указатель на...

Передача указателя в функцию
Здраствуйте. Если не охота читать гору текста то этот абзац + последущий за ним код можете пропустить. Задали на лабе сделать некий...

Передача указателя на функцию
Доброго дня Форумчане. Хотелось бы узнать как вызывать функцию получив на нее указатель? пример class C1 { public: void...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
4
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): Обработчик клика мыши в браузере ПК и касания экрана в браузере на мобильном устройстве
8Observer8 02.02.2026
Содержание блога Для начала пошагово создадим рабочий пример для подготовки к экспериментам в браузере ПК и в браузере мобильного устройства. Потом напишем обработчик клика мыши и обработчик. . .
Философия технологии
iceja 01.02.2026
На мой взгляд у человека в технических проектах остается роль генерального директора. Все остальное нейронки делают уже лучше человека. Они не могут нести предпринимательские риски, не могут. . .
SDL3 для Web (WebAssembly): Вывод текста со шрифтом TTF с помощью SDL3_ttf
8Observer8 01.02.2026
Содержание блога В этой пошаговой инструкции создадим с нуля веб-приложение, которое выводит текст в окне браузера. Запустим на Android на локальном сервере. Загрузим Release на бесплатный. . .
SDL3 для Web (WebAssembly): Сборка C/C++ проекта из консоли
8Observer8 30.01.2026
Содержание блога Если вы откроете примеры для начинающих на официальном репозитории SDL3 в папке: examples, то вы увидите, что все примеры используют следующие четыре обязательные функции, а. . .
SDL3 для Web (WebAssembly): Установка Emscripten SDK (emsdk) и CMake для сборки C и C++ приложений в Wasm
8Observer8 30.01.2026
Содержание блога Для того чтобы скачать Emscripten SDK (emsdk) необходимо сначало скачать и уставить Git: Install for Windows. Следуйте стандартной процедуре установки Git через установщик. . . .
SDL3 для Android: Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 29.01.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами. Версия v3 была полностью переписана на Си, в. . .
Инструменты COM: Сохранение данный из VARIANT в файл и загрузка из файла в VARIANT
bedvit 28.01.2026
Сохранение базовых типов COM и массивов (одномерных или двухмерных) любой вложенности (деревья) в файл, с возможностью выбора алгоритмов сжатия и шифрования. Часть библиотеки BedvitCOM Использованы. . .
SDL3 для Android: Загрузка PNG с альфа-каналом с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 28.01.2026
Содержание блога SDL3 имеет собственные средства для загрузки и отображения PNG-файлов с альфа-каналом и базовой работы с ними. В этой инструкции используется функция SDL_LoadPNG(), которая. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru