QPushButton *btn = new QPushButton;
// 方式一:老式写法
connect(btn, SIGNAL(clicked()), this, SLOT(close()));
// 方式二:Qt5后新写法
connect(btn, &QPushButton::clicked, this, &MainWindow::close);
// 方式三:lambda表达式
connect(btn, &QPushButton::clicked, this, [&]() {
this->close();
});
方式一 老式写法,在编译的时候即使信号或槽不存在也不会报错,但是在执行的时候无效,对于C++这种静态语言来说,这是不友好的,不利于调试;
方式二 Qt5后推荐的写法,如果编译的时候信号或槽不存在是无法编译通过的,相当于编译时检查,不容易出错,还有就是槽的写法可以直接写在public控制域下,不一定非要写在public slots:控制域下;
方式三 采用了lambda表达式的写法,更加方便快捷。
关于lambda需要注意一点:
QTimer::singleShot(3000, /* this, */ [&]{
this->close();
});
connect(btn, &QPushButton::clicked, /* this, */ [&]() {
this->close();
});
看下上面的示例,当我们用lambda表达式的时候,槽的接收者QObject是可以省略不写的,这时候Qt会默认发射者与接收者属于同一个QObject;
//connect to a functor
template <typename Func1, typename Func2>
static inline typename std::enable_if<QtPrivate::FunctionPointer<Func2>::ArgumentCount == -1, QMetaObject::Connection>::type
connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal, Func2 slot)
{
return connect(sender, signal, sender, slot, Qt::DirectConnection);
}
当我们省略槽函数接收者QObject时,那我们就必须要注意lambda内成员的生命周期;例如示例的singleShot,若在槽函数响应前,this已经销毁变为无效指针,后果就会很严重!!!
为什么?
我们知道,connect的发射者与接收者任意一个销毁,那么这个connect就已经断开了;当我们省略接收者QObject的时候,发射者与接收者属于同一个QObject;在上面的示例中,信号槽connect关联依然存在,信号槽依然会触发,但此时this已经被销毁就不好玩了!