在上一篇简单实现Qt的信号槽中,我们简单模拟了Qt的信号槽,从信号发出到槽函数调用我们已经基本了解了,但一些Qt自带的信号是怎么发射出来的呢?今天我们就来深扒一下。
为了方便起见,我们先找一张Qt继承关系图
上图为网上找的,原图连接在这里,侵删
然后,我们随便建个Qt工程,添加一个pushButton,并绑定clicked信号,将断点下在我们的槽函数上,调试程序,点击pushButton,程序会断在我们的槽函数,并得到从main函数开始的调用堆栈,我们逐层的观察
在堆栈的最底层是WinMain函数,没做过windows开发的小伙伴可能会对这个函数感到陌生,这个是windows应用程序的入口函数,我们来看一下这个函数
extern "C" int APIENTRY WinMain(HINSTANCE, HINSTANCE, LPSTR /*cmdParamarg*/, int /* cmdShow */)
{
int argc;
wchar_t **argvW = CommandLineToArgvW(GetCommandLineW(), &argc);
if (!argvW)
return -1;
char **argv = new char *[argc + 1];
for (int i = 0; i < argc; ++i)
argv[i] = wideToMulti(CP_ACP, argvW[i]);
argv[argc] = Q_NULLPTR;
LocalFree(argvW);
const int exitCode = main(argc, argv);
for (int i = 0; i < argc && argv[i]; ++i)
delete [] argv[i];
delete [] argv;
return exitCode;
}
这个函数主要是处理的命令行参数,然后调用Qt工程自动创建的main函数,该函数没做什么特别的事情,主要是处理跨平台问题,可以不用多研究,我们继续往上层走
这一层来到了我们最熟悉的main函数,通常这个函数做的事情也不多,而且主要都是我们自己要做的事,也就不贴代码了,值得深扒也就有是return a.exec();这么一句,正好堆栈也停留在这一句上,我们继续往上走,看a.exec()函数干了什么
我们跳了几层看到,a.exec()只是不断的调用父类的方法,直到QCoreApplication::exec才是真正的函数实现,我们来看一下这个函数
int QCoreApplication::exec()
{
if (!QCoreApplicationPrivate::checkInstance("exec"))
return -1;
QThreadData *threadData = self->d_func()->threadData;
if (threadData != QThreadData::current()) {
qWarning("%s::exec: Must be called from the main thread", self->metaObject()->className());
return -1;
}
if (!threadData->eventLoops.isEmpty()) {
qWarning("QCoreApplication::exec: The event loop is already running");
return -1;
}
threadData->quitNow = false;
QEventLoop eventLoop;
self->d_func()->in_exec = true;
self->d_func()->aboutToQuitEmitted = false;
int returnCode = eventLoop.exec();
threadData->quitNow = false;
if (self) {
self->d_func()->in_exec = false;
if (!self->d_func()->aboutToQuitEmitted)
emit self->aboutToQuit(QPrivateSignal());
self->d_func()->aboutToQuitEmitted = true;
sendPostedEvents(0, QEvent::DeferredDelete);
}
return re