Qt源码解析3-信号和槽机制-展开式分析

Qt源码解析 索引

目录

Qt源码解析 索引

1、源代码

2、展开式

3、信号槽的展开

4、OBJECT宏的展开


1、源代码

class QtSingalSlotTest : public QWidget
{
    Q_OBJECT
​
public:
    QtSingalSlotTest(QWidget *parent = Q_NULLPTR);
​
signals:
    void mySignal();
    void mySingal1(int );
    void mySingal2(QString &,int);
public slots:
    void mySlot();
    void mySlot2(int );
​
private:
    Ui::QtSingalSlotTestClass ui;
    int mValue;
};
​
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QtSingalSlotTest w;
    QObject::connect(&w, SIGNAL(mySignal()), &w, SLOT(mySlot()));
    w.mySignal();
    w.show();
    return a.exec();
}

2、展开式

class QtSingalSlotTest : public QWidget
{
    public: __pragma(warning(push))  static const QMetaObject staticMetaObject; virtual const QMetaObject *metaObject() const; virtual void *qt_metacast(const char *); virtual int qt_metacall(QMetaObject::Call, int, void **); static inline QString tr(const char *s, const char *c = nullptr, int n = -1) { return staticMetaObject.tr(s, c, n); } __declspec(deprecated) static inline QString trUtf8(const char *s, const char *c = nullptr, int n = -1) { return staticMetaObject.tr(s, c, n); } private:   static void qt_static_metacall(QObject *, QMetaObject::Call, int, void **); __pragma(warning(pop)) struct QPrivateSignal {}; 
​
public:
    QtSingalSlotTest(QWidget *parent = nullptr);
​
public :
    void mySignal();
    void mySingal1(int );
    void mySingal2(QString &,int);
public :
    void mySlot();
    void mySlot2(int );
​
private:
    Ui::QtSingalSlotTestClass ui;
    int mValue;
};
​
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QtSingalSlotTest w;
    QObject::connect(
        &w, qFlagLocation("2""mySignal()" "\0" "d:\\work\\qt\\qtsingalslottest\\main.cpp" ":" "8"), 
        &w, qFlagLocation("1""mySlot()" "\0" "d:\\work\\qt\\qtsingalslottest\\main.cpp" ":" "8"));
    w.mySignal();
    w.show();
    return a.exec();
}
​

对比发现,去除相容信息,根据源码逻辑换行:

此展示与moc_*文件对应上,查看重点内容。

class QtSingalSlotTest : public QWidget
{
public: 
   __pragma(warning(push))  //是保存当前的编译器警告状态
   static const QMetaObject staticMetaObject; //上一文章中,元数据信息
   virtual const QMetaObject *metaObject() const;
   virtual void *qt_metacast(const char *);
   virtual int qt_metacall(QMetaObject::Call, int, void **); 
   static inline QString tr(const char *s, const char *c = nullptr, int n = -1)
   { 
       return staticMetaObject.tr(s, c, n); 
   } 
    __declspec(deprecated) 
    /*Q_OBJECT_NO_ATTRIBUTES_WARNING
    与#pragma deprecated()的作用相同。用于指定函数的某个重载形式是不推荐的。当在程序中调用了被deprecated修饰的函数时,编译器将给出C4996警告,并且可以指定具体的警告信息。该警告信息可以来源于定义的宏。
    */
    static inline QString trUtf8(const char *s, const char *c = nullptr, int n = -1) 
    { 
        return staticMetaObject.tr(s, c, n); 
    } 
    private:   
    static void qt_static_metacall(QObject *, QMetaObject::Call, int, void **);              __pragma(warning(pop)) //恢复原先的警告状态
    struct QPrivateSignal 
    {}; 
​
    
    //main函数中connect展开
    QObject::connect(
        &w, qFlagLocation("2""mySignal()" "\0" "d:\\qt\\qtsingalslottest\\main.cpp" ":" "8"), 
        &w, qFlagLocation("1""mySlot()" "\0" "d:\\qt\\qtsingalslottest\\main.cpp" ":" "8"));
​

3、信号槽的展开

​
#ifndef QT_NO_META_MACROS
#ifndef QT_NO_DEBUG
# define QLOCATION "\0" __FILE__ ":" QT_STRINGIFY(__LINE__)
# ifndef QT_NO_KEYWORDS
#  define METHOD(a)   qFlagLocation("0"#a QLOCATION)
# endif
# define SLOT(a)     qFlagLocation("1"#a QLOCATION)
# define SIGNAL(a)   qFlagLocation("2"#a QLOCATION)
#else
# ifndef QT_NO_KEYWORDS
#  define METHOD(a)   "0"#a
# endif
# define SLOT(a)     "1"#a
# define SIGNAL(a)   "2"#a
#endif

上面是信号槽的宏定义。此较简单,先分析此宏。与2中的展开式对比,发现,信号槽的宏在connect函数中就是字符串,debug模式下,会将文件与行数带入,方便调试。

简单形式如下。

QObject::connect(&w, "2""mySignal()", &w, "1""mySlot()");

4、OBJECT宏的展开

宏展开也是上一篇文章中,元数据staticMetaObject变量的信息。

从调试堆栈中看到变量的赋值结果。

源代码中经常看到

QMetaObjectPrivate::get(smeta)->revision

或者

priv(m->d.data)->revision >= 7

这都与一个static const uint qt_meta_data_QtSingalSlotTest[]结构有关。

这两个语句的具体实现如下:

static inline const QMetaObjectPrivate *priv(const uint* data)
{ return reinterpret_cast<const QMetaObjectPrivate*>(data); }
static inline const QMetaObjectPrivate *get(const QMetaObject *metaobject)
{ return reinterpret_cast<const QMetaObjectPrivate*>(metaobject->d.data); }

这两个函数本质是一样的。都是把static const uint qt_meta_data_QtSingalSlotTest[]这个结构的内存块直接转化位QMetaObjectPrivate结构体。因为QMetaObjectPrivate结构体的内存布局和数组的内存布局是一致的。在生成的moc_*文件中,static const uint qt_meta_data_QtSingalSlotTest[]这个结构的注释块中共也是可以和下面的结构体进行对应上的。

struct QMetaObjectPrivate
{
    // revision 7 is Qt 5.0 everything lower is not supported
    // revision 8 is Qt 5.12: It adds the enum name to QMetaEnum
    enum { OutputRevision = 8 }; // Used by moc, qmetaobjectbuilder and qdbus
int revision;
int className;
int classInfoCount, classInfoData;
int methodCount, methodData;
int propertyCount, propertyData;
int enumeratorCount, enumeratorData;
int constructorCount, constructorData;
int flags;
int signalCount;
}
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

道格拉斯范朋克

播种花生牛奶自留田

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值