qt6 connect函数调用中使用SIGNAL、SLOT宏 和 使用成员函数指针的区别及原理


前言

用过qt信号与槽机制的人应该都知道,qt中connect函数可以有两种写参数的方式,第一种是SIGNAL()和SLOT()宏,第二种是&App::member 函数指针,昨天突然发现有时候用第二种方式编译会报错

no matching member function for call to 'connect'

用第一种宏函数的时候就不会报错,并且能编译通过,因此对这两种方式做了一下区分

一、先说结论

第一种用SIGNAL和SLOT宏的方式,信号函数参数列表数量小于槽函数参数列表数量的情况下 可以通过编译,但是会运行时报错

qt.core.qobject.connect: QObject::connect: Incompatible sender/receiver arguments

同时,使用宏函数的方式可以显式指定信号与槽函数的重载版本
并且此方式无需考虑类的继承关系,编译器智能识别基类的槽函数


第二种用&App::member 函数指针的方式,信号函数参数列表数量小于槽函数参数列表数量的情况下 不可以通过编译,同时会显示报错

no matching member function for call to 'connect'

使用函数指针的方式,无法指定信号与槽函数的重载版本,如果函数有重载,则会产生二义性冲突

二、错误原因及原理

1.SIGNAL和SLOT宏的工作原理

宏函数将信号和槽函数转换为const char *类型的字符串,并调用connect的如下重载版本

QMetaObject::Connection QObject::connect(const QObject *sender, const char *signal, 
                                         const QObject *receiver, const char *method, 
                                         Qt::ConnectionType type = Qt::AutoConnection)

将信号与槽函数转换为字符串之后,编译器不会考虑参数是否匹配,只能编译后运行时进行异常检测,并且由于是显示写出了参数列表,指定了函数的重载版本,因此不存在二义性冲突

2.&App::member 函数指针的工作原理

&App::member函数指针形式将自身作为参数传递给connect的如下重载版本

template <typename PointerToMemberFunction> 
QMetaObject::Connection QObject::connect(const QObject *sender, PointerToMemberFunction signal, 
                                         const QObject *receiver, PointerToMemberFunction method, 
                                         Qt::ConnectionType type = Qt::AutoConnection)

可以看出信号与槽函数使用同一个模板参数<typename PointerToMemberFunction>,因此当信号与槽函数参数一致时调用此重载版本

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,
        const QObject *context, Func2 slot,
        Qt::ConnectionType type = Qt::AutoConnection)

可以看出当信号与槽函数参数不一致时,调用此重载版本,但是由于函数指针调用时无法显式指定信号与槽函数的重载版本,即会产生二义性冲突
例如:

QPushbutton *button;
QSignalMapper *signal_mapper;
connect(button, &QPushButton::clicked, signal_mapper, &QSignalMapper::map);

上例中QSignalMapper类具有map的两个不同重载版本

void QSignalMapper::map(QWidget*);
void QSignalMapper::map();

因此会报错

no matching member function for call to 'connect'

qt6 官方文档对于QSignalMapper的Detailed Description中的案例,就是这样写的,但是实际编译时会报错


总结

1、在信号与槽函数不存在重载版本的时候,才可以使用函数指针的方式进行connect连接,否则编译会有二义性冲突
2、任何情况都可以使用SIGNAL与SLOT宏函数进行连接,都可以编译成功,但是可能会运行时异常报错

  • 3
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值