Qtшные signal-slots основаны на знании мета-информации (RTTI,
Reflection, OLE/COM etc.) - это, когда "изнутри кода" известно "всё"
о методах класса, функциях и имеется способ "добраться" до их указателей
(function pointers).
Альтернативные методы здесь:
http://en.wikipedia.org/wiki/Signals_and_slots
> Как концептуально это сделать? Ищу любую информацию по этой теме.
1. libsig++ -- но оно для ++
2. википедия
3. GObject
4. Objective C, передача сообщений, исходники POC и ObjC runtime на Си
5. лисп, generic function в CLOS; разница vtable и generic function
6. конечные автоматы, Ragel, SWITCH-технология
7. io, javascript, self -- прототипы, слоты, интроспекция
...
а то, как реализуется взаимодействие сигнал-слот на Qt (довелось изучать в рамках одного проекта, ибо глюк надо было найти) - это (еле сдерживая мат) жесть полная..
каждый частный сигнал передавал в общую функцию свой id, там он распознавался, вызывался внутренний частный обработчик, они уже опять генерили какой-то id, передавали в общую функцию, а она уже распознавала и вызывала слот. что-то в этом духе было...
причем, там чуть ли не case-ы были...
ух, как вспомню, мурашки по коже.
дело было правда года 1,5 назад. как сейчас - не знаю.
> а то, как реализуется взаимодействие сигнал-слот на Qt (довелось изучать в рамках одного проекта, ибо глюк надо было найти) - это (еле сдерживая мат) жесть полная..
> каждый частный сигнал передавал в общую функцию свой id, там он распознавался, вызывался внутренний частный обработчик, они уже опять генерили какой-то id, передавали в общую функцию, а она уже распознавала и вызывала слот. что-то в этом духе было...
> причем, там чуть ли не case-ы были...
> ух, как вспомню, мурашки по коже.
> дело было правда года 1,5 назад. как сейчас - не знаю.
Вот интересно как оно в Qt устроено в принципе. И как оно будет работать если есть много (сотни-тысячи) связок сигнал-слот. Может такая архитектура мне и не нужна. Привлекает то, что все скрыто от программиста и просто делаются connect-ты. Правда эта простота во-многом за счет moc-а, но может как-то можно было бы это дело макросами сделать.
А switch/case есть по крайней мере в генерируемых moc-файлах.
> А switch/case есть по крайней мере в генерируемых moc-файлах.
Правда чоль? Если да - то даже гений Тролльтехов оказался бессилен перед кривизной недоязычка. Когда в ОО языке нельзя реализовать нормальный ОО без свитчей... Ха!
Ну вот, например, что оно сгенерило для моего класса MainWindow:
int MainWindow::qt_metacall(QMetaObject::Call _c, int _id, void **_a) { _id = QMainWindow::qt_metacall(_c, _id, _a); if (_id < 0) return _id; if (_c == QMetaObject::InvokeMetaMethod) { switch (_id) { case 0: projectDeleted((*reinterpret_cast< QWidget*(*)>(_a[1]))); break; case 1: about(); break; case 2: newFile(); break; case 3: open(); break; case 4: openRecentFile(); break; case 5: save(); break; case 6: saveAs(); break; case 7: close(); break; case 8: closeall(); break; case 9: prefs(); break; case 10: updateWindowMenu(); break; case 11: setActiveSubWindow((*reinterpret_cast< QWidget*(*)>(_a[1]))); break; case 12: importdata(); break; case 13: fullscreen(); break; case 14: ToolsGEDint(); break; case 15: ToolsImageViewer(); break; case 16: ToolsPeriodicTable(); break; case 17: explorerTabChanged((*reinterpret_cast< int(*)>(_a[1]))); break; case 18: updateMenusState(); break; } _id -= 19; } return _id; }
case 1-18 - это мои функции, объявленные как SLOT. case 0 - это мой собственный сигнал.
Есть у меня подозрение, что в Qt делается полный обход всех возможных слотов всех объектов при возникновении сигнала. Это, конечно, плохо (если правда).
Ну вот, например, что оно сгенерило для моего класса MainWindow:
int MainWindow::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
{
_id = QMainWindow::qt_metacall(_c, _id, _a);
if (_id < 0)
return _id;
if (_c == QMetaObject::InvokeMetaMethod) {
switch (_id) {
case 0: projectDeleted((*reinterpret_cast< QWidget*(*)>(_a[1]))); break;
case 1: about(); break;
case 2: newFile(); break;
case 3: open(); break;
case 4: openRecentFile(); break;
case 5: save(); break;
case 6: saveAs(); break;
case 7: close(); break;
case 8: closeall(); break;
case 9: prefs(); break;
case 10: updateWindowMenu(); break;
case 11: setActiveSubWindow((*reinterpret_cast< QWidget*(*)>(_a[1]))); break;
case 12: importdata(); break;
case 13: fullscreen(); break;
case 14: ToolsGEDint(); break;
case 15: ToolsImageViewer(); break;
case 16: ToolsPeriodicTable(); break;
case 17: explorerTabChanged((*reinterpret_cast< int(*)>(_a[1]))); break;
case 18: updateMenusState(); break;
}
_id -= 19;
}
return _id;
}
case 1-18 - это мои функции, объявленные как SLOT.
case 0 - это мой собственный сигнал.
Есть у меня подозрение, что в Qt делается полный обход всех возможных слотов всех объектов при возникновении сигнала. Это, конечно, плохо (если правда).
В общем для моей задачи думается просто сделать в каждом объекте динамический список callback-ов и указателей на другие объекты, которые будут передаваться в эти callback-и.
Кутишные сигналы со слотами -- всего лишь извращенный вызов коллбэков.
> ...думается просто сделать в каждом объекте динамический список callback-ов и указателей на другие объекты, которые будут передаваться в эти callback-и.
Вообще говоря, есть даже специальный design pattern "Observer", который является более общим.
Я б просто в каждом объекте с "сигналами" определил массив списков каллбэков. Сами сигналы -- целые (именованные) константы, индексирующие этот массив. При "связывании" сигнала со "слотом" к соответствующему элементу массива добавляется ссылка на callback (т.е., на этот слот). А параметры передавать можно просто универсально, через void *.
> Вообще говоря, есть даже специальный design pattern "Observer", который является более общим.
> Я б просто в каждом объекте с "сигналами" определил массив списков каллбэков. Сами сигналы -- целые (именованные) константы, индексирующие этот массив. При "связывании" сигнала со "слотом" к соответствующему элементу массива добавляется ссылка на callback (т.е., на этот слот). А параметры передавать можно просто универсально, через void *.
Да-да, примерно так я себе это и представляю. Только мутновато пока все в голове. Нужно делать, там прояснится.
> А Си++ не утверждает, что он динамически типизирован.
Не в тему! Это трольтеховская поделка -- не совсем С++ на самом деле.
Сигнал-слот не требует офигенной динамической типизации, и делается с шаблонами вполне прилично (как обычно, статически типизровано, т.е. более надежно, чем у трольтехов)
(А плюсы достаточно прилично динамически типизированы, хотя не спорю, что там проблемы можно найти, но НЕ для этого случая ИМХО).
>> А switch/case есть по крайней мере в генерируемых moc-файлах.
> Правда чоль? Если да - то даже гений Тролльтехов оказался бессилен перед кривизной недоязычка. Когда в ОО языке нельзя реализовать нормальный ОО без свитчей... Ха!
Ничего подобного. Это трольтехи писали свою фигню, когда компиляторы не держали шаблоны должным образом, а сейчас все переписывать под С++ не хотят.