Форум программистов, компьютерный форум CyberForum.ru
Наши страницы

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
Рейтинг: Рейтинг темы: голосов - 57, средняя оценка - 4.98
dimon1984
40 / 38 / 0
Регистрация: 22.01.2011
Сообщений: 670
#1

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

06.05.2011, 22:33. Просмотров 7935. Ответов 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)
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
06.05.2011, 22:33
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Передача указателя на метод в функцию (C++):

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

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

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

Передача указателя на функцию - C++
Есть класс в котором: typedef void(*setChar)(int x, int y, wchar_t c); void Paint(setChar SetChar) В другом классе...

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

Передача указателя в функцию - C++
Здравствуйте. Прошу помощи, сижу уже пару часов читаю мануалы, но так и не смог до конца понять, что мне делать. Есть вот такой код: ...

3
CyBOSSeR
Эксперт С++
2303 / 1673 / 86
Регистрация: 06.03.2009
Сообщений: 3,675
06.05.2011, 22:39 #2
dimon1984, потому что методы (функции-члены) по факту принимает на один аргумент больше чем указано в списке аргументов - указатель на объект для которого вызывается метод. Получается Вы в функцию ожидающую указатель на функцию принимающую один аргумент передаете указатель на функцию принимающую два аргумента (this и lParam). Самое простое сделать метод статическим и тогда проблема решится.
2
ValeryLaptev
Эксперт С++
1041 / 820 / 48
Регистрация: 30.04.2011
Сообщений: 1,659
06.05.2011, 22:57 #3
Лучший ответ Сообщение было отмечено автором темы, экспертом или модератором как ответ
Вот ликбез по обоим видам указателей:

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

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

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

Рассмотрим несколько простых примеров. Допустим, у нас объявлен указатель на функцию:
Код
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 байт!
7
dimon1984
40 / 38 / 0
Регистрация: 22.01.2011
Сообщений: 670
07.05.2011, 00:09  [ТС] #4
дополню. Нашёл полезный пример:
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
07.05.2011, 00:09
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
07.05.2011, 00:09
Привет! Вот еще темы с ответами:

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

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

передача указателя на функцию - C++
Помогите исправить ошибку уже незнаю как быть В бивает ту ошибку error C2664: Generate: невозможно преобразовать параметр 2 из &quot;void&quot;...

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


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

Или воспользуйтесь поиском по форуму:
4
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru