baldr
|
|
« : 16-10-2004 12:21 » |
|
Вот, к примеру, такой кусок кода: typedef void (CALLBACK aNOT) (int* ii); typedef aNOT* P_NOTa;
class zzz { public: void CALLBACK zasd (INT *f) { /**/ } // Line X1 };
BOOL aaa(P_NOTa ap) { return TRUE; }
void CALLBACK asd (INT *f) // Line X2 { // stuff }
void tmpf() { zzz z; aaa(asd); // Line X3 aaa(z.zasd); // Line X4 }
На строчке X4 возникает ошибка "error C2664: 'aaa' : cannot convert parameter 1 from 'void (int *)' to 'void (__stdcall *)(int *)'" На строчке X3 ошибки НЕ ВОЗНИКАЕТ! Видимо, проблема в том, что zasd() является функцией-членом? Объявления в строчках X1 и X2, в принципе, одинаковые. Вопрос: как мне передать в качестве параметра функцию zasd? Желательно не менять типы в typedef и объявление функции aaa. Уже третий час сижу, закипаю.
|
|
« Последнее редактирование: 02-12-2007 10:40 от Алексей1153++ »
|
Записан
|
Приличный компьютер всегда будет стоить дороже 1000 долларов, потому что 500 долларов - это не вполне прилично
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #1 : 16-10-2004 17:39 » |
|
baldr, никогда не разбирался с указателями на функции ( надо будет как-нибудь разобраться:) ) и не совсем понимаю, как вызвать функцию по её указателю, но вот это компилятор проглотил: typedef void (CALLBACK aNOT) (int* ii); typedef aNOT* P_NOTa;
class zzz { public: void CALLBACK zasd (INT *f) { /**/ } // Line X1 void gluk(int __cdecl (P_NOTa)){ /*здесь я не знаю, что делать*/} };
BOOL aaa(P_NOTa ap) { return TRUE; }
void CALLBACK asd (INT *f) // Line X2 { // stuff }
void tmpf() { zzz z; aaa(asd); // Line X3 z.gluk(aaa); //aaa(z.zasd); // Line X4 }
то есть указатель на aaa передаю в класс zzz, а дальше - фиг его знает :?
|
|
« Последнее редактирование: 02-12-2007 10:41 от Алексей1153++ »
|
Записан
|
|
|
|
Finch
Спокойный
Администратор
Offline
Пол:
Пролетал мимо
|
|
« Ответ #2 : 16-10-2004 20:50 » |
|
baldr, Я не знаю точно для VC++. Для билдера запрешено создавать в классе возрашаемые функции. Что то связано с однообразием вызовов функций в классе. Все функции в классе создаются с моделью _fastcall. И для этого служит специальный макрос, который преврашает функцию в возрашаемую, а затем нужно закрывать этот макрос. Давно я это делал, сейчас точно не помню
|
|
|
Записан
|
Не будите спашяго дракона. Джаффар (Коша)
|
|
|
Finch
Спокойный
Администратор
Offline
Пол:
Пролетал мимо
|
|
« Ответ #3 : 17-10-2004 15:20 » |
|
baldr, Если есть у тебя исходники всех объектов MFC, посмотри как реализовано обрашшение к WinAPI функции RegisterClass (может быть RegisterClassEx). В эту функцию дается параметр в виде структуры WNDCLASS. Один из элементов этой структуры (WNDPROC lpfnWndProc) возврашаемая функция.
|
|
|
Записан
|
Не будите спашяго дракона. Джаффар (Коша)
|
|
|
|
lapulya
Молодой специалист
Offline
|
|
« Ответ #5 : 18-10-2004 06:38 » |
|
baldr, так как у тебя написано компилятор не понимает, что это функция статическая, а поинтер только на статический член класса можно сохранить и вызвать без объекта (хотя с объектом можно и thiscall), так что у тебя два пути 1 пиши так typedef void (CALLBACK aNOT) (int* ii); typedef aNOT* P_NOTa;
class zzz { public: static void CALLBACK zasd (INT *f) { /**/ } // Line X1 };
BOOL aaa(P_NOTa ap) { return TRUE; }
void CALLBACK asd (INT *f) // Line X2 { // stuff }
void tmpf() { zzz z; aaa(asd); // Line X3 aaa(z.zasd); // Line X4 }
2 либо так class zzz; typedef void (CALLBACK zzz::*aNOT ) (int* ii);
class zzz { public: void CALLBACK zasd (INT *f) { /**/ } // Line X1 };
BOOL aaa(aNOT func) { return TRUE; }
void CALLBACK asd (INT *f) // Line X2 { // stuff }
void tmpf() { zzz z; // aaa(asd); // Line X3 // ТАК БОЛЬШЕ НЕ ПРОКАТИТ!!! aaa( &zzz::zasd ); // Line X4 }
|
|
« Последнее редактирование: 02-12-2007 10:43 от Алексей1153++ »
|
Записан
|
С уважением Lapulya
|
|
|
Pu
Большой босс
Offline
78
|
|
« Ответ #6 : 18-10-2004 08:28 » |
|
baldr, А ты работаешь в callback функции с членами класса не статик?
|
|
|
Записан
|
Насколько я опытен? Достаточно, чтобы понимать, что дураков нельзя заставить думать по–другому, но недостаточно, чтобы отказаться от попыток это сделать. (с) Артур Джонс
|
|
|
lapulya
Молодой специалист
Offline
|
|
« Ответ #7 : 18-10-2004 08:39 » |
|
baldr, да ... действительно (заяц, отличный вопрос!!!) а что ты собственно хочешь т.е. почему ты делаешь именно так, а не по другому...
|
|
|
Записан
|
С уважением Lapulya
|
|
|
Mad
Гость
|
|
« Ответ #8 : 18-10-2004 10:49 » |
|
baldr, придется тебе делать так: typedef void (CALLBACK aNOT) (int* ii); typedef aNOT* P_NOTa;
class zzz { public: void zasd (INT *f) { /**/ } // Line X1 };
BOOL aaa(P_NOTa ap) { return TRUE; }
BOOL aaa(zzz& z) { return TRUE; }
void CALLBACK asd (INT *f) // Line X2 { // stuff }
void tmpf() { zzz z; aaa(asd); // Line X3 aaa(z); // Line X4 }
|
|
« Последнее редактирование: 02-12-2007 10:44 от Алексей1153++ »
|
Записан
|
|
|
|
Finch
Спокойный
Администратор
Offline
Пол:
Пролетал мимо
|
|
« Ответ #9 : 18-10-2004 14:59 » |
|
baldr, Это крайний случай. Сделай через функцию друга. 1. Ты получиш полный доступ ко всем переменным класса. 2. При этом твоя функция не будет связана с форматами вызова функций в классе.
|
|
|
Записан
|
Не будите спашяго дракона. Джаффар (Коша)
|
|
|
baldr
|
|
« Ответ #10 : 01-11-2004 16:30 » |
|
Желательно делать в классе... И статической не хочется... Это будет диплом. А для диплома я делаю еще описание в виде UML-диаграмм. И на диаграммах не очень понятно как показать глобальные переменные и вообще отдельные статические функции. Хочу показать класс... А эта функция очень важна...
|
|
|
Записан
|
Приличный компьютер всегда будет стоить дороже 1000 долларов, потому что 500 долларов - это не вполне прилично
|
|
|
Anchorite
Гость
|
|
« Ответ #11 : 01-11-2004 21:03 » |
|
Без static здесь получается полный бред: Если функция является членом класса и не является static, то внутри доступны ВСЕ поля ЭКЗЕМПЛЯРА класса и указатель this ЭКЗЕМПЛЯРА класса, для которого ее вызывают. А у тебя получается что ты хочешь вызвать функцию для несуществующего экземпляра класса. Так что или stattic перед void CALLBACK zasd (INT *f) { /**/ } // Line X1 или BOOL aaa(zzz z) { int n = 0; // Для примера return z.zasd(n); }
|
|
« Последнее редактирование: 02-12-2007 10:45 от Алексей1153++ »
|
Записан
|
|
|
|
npak
|
|
« Ответ #12 : 02-11-2004 11:10 » |
|
baldr, функция-член класса (не статическая), объявленная с одним параметром, на самом деле получает два параметра -- указатель на объект этого класса и собственно аргумент. Можно взять указатель на метод, для этого можно воспользоваться конструкцией Но это НЕ ЕСТЬ указатель на функцию. Это специальная синтаксическая конструкция, которую можно использовать только вызове функции совместно с объектом класса. Например, typedef void (CALLBACK zzz::*P_ZZZ_ZASD); P_ZZZ_ZASD p_zasd = &zzz::zasd; z.*p_zasd(&n);
Отдельное выражение нельзя использовать как указатель на функцию. Если можно, я тебя немного покритикую. То, что ты пытаешься сделать, выглядит как неестественный гибрид процедурного и объектно-ориентированного подходов к событийно-управляемому программированию. Ты пытаешься вызвать метод некоторого объекта в ответ на некоторое событие, я правильно понимаю? Так вот, для этой задачи уже достаточно давно придумали технику, получившую названия "Command" и "Delegate" class AbstractDelegate { public: virtual void operator () (int *) = 0; };
class NegationDelegate : public AbstractDelegate { public: void operator () (int * n) { // Some stuff } };
BOOL aaa(P_NOTa ap) { return TRUE; }
BOOL aaa(AbstractDelegate & ad) { int n; ad(&n); return TRUE; }
void CALLBACK asd (INT *f) // Line X2 { // stuff }
void tmpf() { NegationDelegate nd; aaa(asd); // Line X3 aaa(nd); } В приведённом куске кода создаётся абстрактный класс AbstractDelegate, содержащий оператор функционального вызова с аргументом (int *). Для примера показан потомок делегата, в котором реализован функциональный вызов. Дан пример функции, которая пользуется делегатом для выполнения необходимой операции. IMHO, это более правильный с точки зрения ООП способ передавать управление объекту по событию. Более подробно приём описан здесь: http://www.codeguru.com/Cpp/Cpp/cpp_mfc/article.php/c4119/
|
|
« Последнее редактирование: 02-12-2007 10:46 от Алексей1153++ »
|
Записан
|
|
|
|
lapulya
Молодой специалист
Offline
|
|
« Ответ #13 : 02-11-2004 12:16 » |
|
baldr, А для диплома я делаю еще описание в виде UML-диаграмм. И на диаграммах не очень понятно как показать глобальные переменные и вообще отдельные статические функции. Хочу показать класс... А эта функция очень важна...
На диаграммах отображается, как правило, объекты или классы (в зависимости от диаграммы), со своими свойствами, описывающими состояние (переменные - члены, функции - члены и т.д.), так вот это все пишется для того, что бы понять, как эти объекты всаимосвязаны, откуда текут сообщения для обработки, кто эти сообщения обрабатывает, кто и куда от правляет ответ и т.д. тоесть все что связано с моделированием предметной области и моделированием работы системы, но детали реализации, к каковым относится я подозреваю и твоя функция void CALLBACK zasd (INT *f) { /**/ } // Line X1
поскольку она не общается ни с одним из мемберов (полностью. не зависит от объекта на который указывает this), как раз и является чистейшей деталью реализации, как правило, не отображаются потому как они мало кого волнуют (ну к примеру ты мог эту функцию преписать так что она состоит из вызова еще 30 дополнительных фукций которые например считают значение синуса пи пополам, так чтоже их все на диаграмме рисовать). По этому на диаграммах классов отображать ее не надо! если очень нужно про нее рассказать, то используй стандартную блок-схему для демонстрации ее (функции) алгоритма!!! Если это нивкакую не устраивает ... вынеси эту функцию в отдельный класс, допустим Utility (пусть там она будет полноценным мембером) и далее доступ к объекту типа Utility осуществляй через паттерн Синглетон (который в свою очерез на диаграмме классов можно и не отражать потому как это опять же деталь неализации и она никому кроме тебя лично не интересна)
|
|
|
Записан
|
С уважением Lapulya
|
|
|
Finch
Спокойный
Администратор
Offline
Пол:
Пролетал мимо
|
|
« Ответ #14 : 10-11-2004 17:45 » |
|
|
|
|
Записан
|
Не будите спашяго дракона. Джаффар (Коша)
|
|
|
baldr
|
|
« Ответ #15 : 11-11-2004 08:18 » |
|
:new_goss: lapulya, эта функция является одним из важнейших элементов реализации алгоритма. Поэтому я организовал для нее отдельный класс, что, в целом, правильно, так как она все равно должна работать с различными объектами, созданными в программе. Если делать функцию отдельно, глобальной, то тогда надо для нее инициализировать туеву хучу глобальных переменных. :new_shot: Про ООП тогда можно забыть. Так у меня было сделано ДО этого. Было плохо. Что касается примера npak, то он интересен. Но тут возникает проблема. Уже есть класс, который реализует вызов этой CALLBACK-функции. И его менять нельзя из принципа. Вот оба typedef и функция aaa(...) из моего первоначального примера как раз части, которые менять нельзя. :l_lick_lick: Сейчас сделал в классе статическую функцию. Из-за нее пришлось делать все переменные-члены класса тоже статическими. По-моему, получилось даже еще хуже, чем при использовании глобальных переменных. :new_mpr: И все равно мне до сих пор не понятно почему CALLBACK-функция должна быть static?? :l_smile: Есть конкретный экземпляр класса, ссылку на его функцию я передаю... Что еще надо? Finch, спасибо за ссылку. Но там пишется что оно так, но не пишется почему.
|
|
|
Записан
|
Приличный компьютер всегда будет стоить дороже 1000 долларов, потому что 500 долларов - это не вполне прилично
|
|
|
npak
|
|
« Ответ #16 : 11-11-2004 09:24 » |
|
baldr, сравни:
1. Ты передаёшь указатель на функцию с одним аргументом. В точке вызова функция будет вызвана и ей будет передан один аргумент.
2. Ты передаёшь агрегат [ссылка на объект, указатель на функцию с двумя переменными]. Тем самым ты хочешь от компилятора, чтобы вместо вызова функции с одним аргументом была вызвана функция с двумя аргументами, причём первый -- это указатель на объект, а второй -- аргумент, который передаётся в точке вызова.
Во втором случае информация о том, что это функция, а не метод класса, в точке вызова отстутствует, поэтому получается, что ты хочешь о компилятора, чтобы он сгенерировал временную функцию (на этапе исполнения, заметь), которая вызывает метод и передаёт в него аргумент.
Это нормальное дело для функциональных языков, но в С не реализовано (и унаследовано в С++). Ты можешь попробовать генерить тело функции самостоятельно.
Так что наилучший способ (на мой взгляд), если нет возможности изменить класс, в котором вызывается callback, обойтись без методов класса.
|
|
|
Записан
|
|
|
|
trahomoter
Гость
|
|
« Ответ #17 : 11-11-2004 10:14 » |
|
точно знаю, что на rational rose enterprise edition можно указывать тип переменной, а ты наверняка на нём uml делаешь.
|
|
|
Записан
|
|
|
|
baldr
|
|
« Ответ #18 : 11-11-2004 11:06 » |
|
npak, не с чем поспорить. Но если мы вызываем: class1.func1(&class2.func2()); будет не то же самое? Ссылаемся на функцию-член. А class1.func3(func4); ? Разве описание func1 и func3 будет разным? [вообще-то, что-то в этом есть... наверное, будет... :? ] То есть, подведем небольшой итог: если не переписывать функцию aaa(...) из примера, то выхода два: сделать функцию zasd(...) либо глобальной, либо статической в классе? Я прав? Третьего способа нет? trahomoter, да, это rational rose, ясен пень. Но при чем тут переменная?
|
|
|
Записан
|
Приличный компьютер всегда будет стоить дороже 1000 долларов, потому что 500 долларов - это не вполне прилично
|
|
|
npak
|
|
« Ответ #19 : 11-11-2004 11:48 » |
|
baldr, &class2::func -- это указатель на метод func в классе class2. &::func -- это указатель на глобальную функцию func. C точки зрения языка, это совершенно разные вещи. Во-первых, типы этих указателей друг к другу не приводятся. Во-вторых, эти указатели на функциональные конструкции по-разному вызываются. Причём не только в тексте на с++, но и в сгенерированном коде. если не переписывать функцию aaa(...) из примера, то выхода два: сделать функцию zasd(...) либо глобальной, либо статической в классе? Я прав? Третьего способа нет? По большому счёту да, ты прав. Можно, конечно, предложить грязный хак -- самому генерировать функцию (в машинных кодах), которая будет вызывать метод некоторого объекта. Предсказать в этом случае возможные глюки, если что-то пойдёт не так, я не берусь.
|
|
|
Записан
|
|
|
|
baldr
|
|
« Ответ #20 : 11-11-2004 12:28 » |
|
npak, все понял. Спасибо.
Не нравилось мне это статическое определение... Но lapulya, спасибо за подсказку про шаблон Singleton. Сделал по нему. Теперь относительно удовлетворен.
|
|
|
Записан
|
Приличный компьютер всегда будет стоить дороже 1000 долларов, потому что 500 долларов - это не вполне прилично
|
|
|
|