zoukankan      html  css  js  c++  java
  • Qt 关键宏 转自网络整理

    1.Q_OBJECT

    #define Q_OBJECT 
    public: 
        Q_OBJECT_CHECK 
        static const QMetaObject staticMetaObject; 
        virtual const QMetaObject *metaObject() const; 
        virtual void *qt_metacast(const char *); 
        QT_TR_FUNCTIONS 
        virtual int qt_metacall(QMetaObject::Call, int, void **); 
    private: 
        Q_DECL_HIDDEN_STATIC_METACALL static void qt_static_metacall(QObject *, QMetaObject::Call, int, void **); 
        struct QPrivateSignal {};

    当在头文件定义宏O_OBJECT 时   我们就可以使用信号和槽功能  就是因为其生成了一个moc文件

    QT_TR_FUNCTIONS 这个宏也是在这里定义的。也就是说,如果你要使用 tr() 国际化,就必须使用 Q_OBJECT 宏,否则是没有 tr() 函数的。这期间最重要的就是 virtual const QMetaObject *metaObject() const; 函数。这个函数返回 QMetaObject 元对象类的实例,通过它,你就获得了 Qt 类的反射的能力:获取本对象的类型之类,而这一切,都不需要 C++ 编译器的 RTTI 支持。Qt 也提供了一个类似 C++ 的 dynamic_cast() 的函数 qobject_case(),而这一函数的实现也不需要 RTTI。另外,一个没有定义 Q_OBJECT 宏的类与它最接近的父类是同一类型的。也就是说,如果 A 继承了 QObject 并且定义了 Q_OBJECT,B 继承了 A 但没有定义 Q_OBJECT,C 继承了 B,则 C 的 QMetaObject::className() 函数将返回 A,而不是本身的名字。因此,为了避免这一问题,所有继承了 QObject 的类都应该定义 Q_OBJECT 宏,不管你是不是使用信号槽。

    staticMetaObject 和metaObject 他们都是QOBJECT宏中被声明的 

    实现:

    const QMetaObject MainWindow::staticMetaObject = {
        { &QMainWindow::staticMetaObject, qt_meta_stringdata_MainWindow.data,
          qt_meta_data_MainWindow,  qt_static_metacall, Q_NULLPTR, Q_NULLPTR}
    };
    
    
    const QMetaObject *MainWindow::metaObject() const
    {
        return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject;
    }

    QObject::d_ptr->metaObject 只被用于动态元对象(QML对象),通常虚函数metaObject() 只是返回类的staticMetaObject 。

    staticMetaObject被创建为只读数据。qobjectdefs.h 文件中QMetaObject的定义如下:

    struct QMetaObject
    {
        /* ... Skiped all the public functions ... */
    
        enum Call { InvokeMetaMethod, ReadProperty, WriteProperty, /*...*/ };
    
        struct { // private data
            const QMetaObject *superdata;
            const QByteArrayData *stringdata;
            const uint *data;
            typedef void (*StaticMetacallFunction)(QObject *, QMetaObject::Call, int, void **);
            StaticMetacallFunction static_metacall;
            const QMetaObject **relatedMetaObjects;
            void *extradata; //reserved for future use
        } d;
    };

    2.Q_D宏

    Qt 源码中有很多Q_Q和Q_D宏,使用这些宏的地方总会看到有q指针和d指针,查了查KDE文档,大体搞清了其中的机理,欧也!Qt的这些私有数据访问策略还是挺值得借鉴。下面就简单总结一下。

    D-指针

    共享d指针实现方法如下: 
    1、在基类中定义一个protected权限的d_ptr指针;

    2、在每个派生类中定义d_func(),获取基类d_ptr,并将其转换为当前私有类指针(派生自基类d_ptr)

    3、在函数中使用Q_D,这样就可以使用d了;

    4、在私有数据继承体系中,不要忘记将析构函数定义为虚函数,基类析构函数中释放d_ptr,以防内存泄露!

    5、类的派生,加上protected 构造函数,调用父类构造函数,将私有数据类传参; 

    // 在主类中的Private Data 声明,Q_D使用之 
    #define Q_DECLARE_PRIVATE(Class)  
        inline Class##Private* d_func() { return reinterpret_cast<Class##Private *>(qGetPtrHelper(d_ptr)); }  
        inline const Class##Private* d_func() const { return reinterpret_cast<const Class##Private *>(qGetPtrHelper(d_ptr)); } 
        friend class Class##Private; 
    // 在主类中的Private Data 声明(在d指针命名非d_ptr而是Dptr情况下使用),Q_D使用之 
    #define Q_DECLARE_PRIVATE_D(Dptr, Class) 
        inline Class##Private* d_func() { return reinterpret_cast<Class##Private *>(Dptr); }
        inline const Class##Private* d_func() const { return reinterpret_cast<const Class##Private *>(Dptr); }  
        friend class Class##Private; 

    #define Q_D(Class) Class##Private * const d = d_func() 

    Q指针

    搞清了d指针,q指针就简单多了,有没有发现’q’和’d’哪里有点像,是滴!’q’就是’d’倒过个来。q指针的方向正好和d指针相反,它是在私有数据类中使用的(d指针只在主类中使用,就是使用私有数据类的那个类,真拗口!),来获取主类指针。 

    // 在私有数据类中的Public Data声明,Q_Q使用之 
    #define Q_DECLARE_PUBLIC(Class)   
        inline Class* q_func() { return static_cast<Class *>(q_ptr); }  
        inline const Class* q_func() const { return static_cast<const Class *>(q_ptr); }  
        friend class Class; 
    #define Q_Q(Class) Class * const q = q_func() 

    感 觉Qt的这种机制破坏了OO,我想这就是它为何只做内部使用的原因吧。。。   有点完全依赖宏的味道,不像它的signal/slot,通过moc编译插入元数据。不过还是方便hack了。至于signal/slot,我想应该可 以通过macro和函数指针来作为替代方案,改天再see see。这里只是把看到的关于D指针的文章和自己的体会简单总结翻译一下,更详细的可以看下面两个连接。 

     
  • 相关阅读:
    oracle11g windows客户端安装
    leetcode做题总结
    后端工程师都应该知道的最佳实践
    阿里云ubuntu下nginx部署上线后报错问题
    漫谈逆向工程
    RPC远程过程调用(Remote Procedure Call)
    stub和proxy使用初衷
    vue如何绑定多个class style
    简单又好看的背景 , 代码实现方格背景
    使用C#.NET调用ICU进行编码检测和编码转换
  • 原文地址:https://www.cnblogs.com/laien/p/5537512.html
Copyright © 2011-2022 走看看