Qt宏Q_OBJECT展开记录



  • c++中的宏

    #define A 3.14 展开后把A替换为B

    #define A(a) #a 展开后用a的字符串替换A(a)

    #define A(a) a##B 展开后把a和B的字符串连接起来后替换A(a)

    #include "common/common.h"
    #define PI 3.14
    #define PIPrivate 3.1415
    #define foo(arg) #arg
    #define bar(arg) arg##Private
    int main(int argc, char *argv[]) {
    
        DApplication::loadDXcbPlugin();
        DApplication app(argc, argv);
        Dtk::Util::DLogManager::registerConsoleAppender();
        Dtk::Util::DLogManager::registerFileAppender();
        qDebug()<<PI<<foo(PI)<<bar(PI)<<foo(bar(PI));
        return 0;
    }
    
    

    源码地址:GitHub

    在Qt中,用了不少的宏。最常见的就是Q_OBJECT

    Q_OBJECT展开的最终效果如下

    public:
        template<typename ThisObject>
        inline void qt_check_for_QOBJECT_macro(const ThisObject &_q_argument) const {
            int i = qYouForgotTheQ_OBJECT_Macro(this, &_q_argument);
            i = i + 1;
        }
        _Pragma(GCC diagnostic 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 = Q_NULLPTR, int n = -1) {
            return staticMetaObject.tr(s, c, n);
        }
    
        static inline QString trUtf8(const char *s, const char *c = Q_NULLPTR, int n = -1) {
            return staticMetaObject.tr(s, c, n);
        }
    private:
        __attribute__((visibility("hidden"))) static void qt_static_metacall(QObject *, QMetaObject::Call, int, void **);
        _Pragma(GCC diagnostic pop)
        struct QPrivateSignal {};
    

    下面做一步步展开
    Q_OBJECT展开后如下,又有不少的宏

    public: 
        Q_OBJECT_CHECK 
        QT_WARNING_PUSH 
        Q_OBJECT_NO_OVERRIDE_WARNING 
        static const QMetaObject staticMetaObject; 
        virtual const QMetaObject *metaObject() const; 
        virtual void *qt_metacast(const char *); 
        virtual int qt_metacall(QMetaObject::Call, int, void **); 
        QT_TR_FUNCTIONS 
    private: 
        Q_OBJECT_NO_ATTRIBUTES_WARNING 
        Q_DECL_HIDDEN_STATIC_METACALL static void qt_static_metacall(QObject *, QMetaObject::Call, int, void **); 
        QT_WARNING_POP 
        struct QPrivateSignal {}; 
        QT_ANNOTATE_CLASS(qt_qobject, "")
    

    Q_OBJECT_CHECK展开如下,宏越来越多了。

    template<typename ThisObject>
    inline void qt_check_for_QOBJECT_macro(const ThisObject &_q_argument) const {
        int i = qYouForgotTheQ_OBJECT_Macro(this, &_q_argument);
        i = i + 1;
    }
    

    QT_WARNING_PUSHQT_WARNING_POP展开

    #define QT_WARNING_PUSH QT_DO_PRAGMA(GCC diagnostic push)
    #define QT_WARNING_POP QT_DO_PRAGMA(GCC diagnostic pop)
    

    QT_DO_PRAGMA展开

    #define QT_DO_PRAGMA(text)                      _Pragma(#text)
    

    又来了新的宏_Pragma,参考2.1.3 _Pragma操作符,就是告诉编译器GCC diagnostic push

    Q_OBJECT_NO_OVERRIDE_WARNING展开

    #if defined(Q_CC_CLANG) && Q_CC_CLANG >= 306
    #  define Q_OBJECT_NO_OVERRIDE_WARNING      QT_WARNING_DISABLE_CLANG("-Winconsistent-missing-override")
    #else
    #  define Q_OBJECT_NO_OVERRIDE_WARNING
    #endif
    
    

    QT_TR_FUNCTIONS展开,QT_DEPRECATED展开为空

    static inline QString tr(const char *s, const char *c = Q_NULLPTR, int n = -1) {
        return staticMetaObject.tr(s, c, n);
    }
    
    QT_DEPRECATED static inline QString
    trUtf8(const char *s, const char *c = Q_NULLPTR, int n = -1) {
        return staticMetaObject.tr(s, c, n);
    }
    

    Q_OBJECT_NO_ATTRIBUTES_WARNING展开,QT_WARNING_DISABLE_GCC展开为空

    #define Q_OBJECT_NO_ATTRIBUTES_WARNING QT_WARNING_DISABLE_GCC("-Wattributes")
    

    Q_DECL_HIDDEN_STATIC_METACALL展开,出现了__attribute__黑魔法,参考ATTRIBUTE 你知多少?

    #define Q_DECL_HIDDEN_STATIC_METACALL Q_DECL_HIDDEN
    #define Q_DECL_HIDDEN     __attribute__((visibility("hidden")))
    

    QT_ANNOTATE_CLASS展开为空

    #define QT_ANNOTATE_CLASS(type, ...)
    

    参考文章
    2.1.3 _Pragma操作符
    ATTRIBUTE 你知多少?

    源码地址:GitHub



  • @大黄老鼠 宏魔法真心黑啊



  • @大黄老鼠 因为GCC大家庭主要使用的是__attribute__修饰。
    而MSVC可以在类名或者函数名前面修饰。比如说__stdcall__declspec(dllexport)



  • @jiangcaiyang c++各种黑魔法,我怀恋java



  • @大黄老鼠Qt宏Q_OBJECT展开记录 中说:

    GitHub

    能变出钱来的魔法就是好魔法,人家用易语言的也有发了大财的。



  • @stlcours 支持一个。不管用什么语言,不断完善自己的产品才是正确的道路。


Log in to reply
 

走马观花

最近的回复

  • 113.jpg
    1、什么是lambda表达式,什么是闭包?
    lambda表达式即lambda函数,也就是匿名函数。

    lambda表达式在C++中包含了
    []表示捕获
    ()是函数的参数,需要指定类型
    ->type是返回的类型,可以省略,如果编译器无法推出类型的话可以强制编写
    {}是函数体。

    lambda可以被声明为mutable的,作用是将捕获的内容进行改变。
    闭包是函数的定义以及定义函数时提供的环境,总称为闭包。lambda函数也是一种闭包。
    lambda本身是匿名函数,而捕获语句则是提供了定义函数时提供的环境。

    2、什么是右值引用?
    右值引用相对与左值引用而言的。左值即=运算符左边的变量,右值是=运算符右边的常量或变量。由此可以看出,
    右值引用指的是对常量或变量的引用。它的用途包含了移动语义和完美转发。
    移动语义就是弥补了C++历史在处理变量传递时丢失的一种语义。它和值传递、引用传递一样,是变量传递的方式之一。
    如果没有移动语义,为了将一个类的实例传递给另外一个实例,就需要额外地进行构造、赋值、销毁的操作。
    对于一些比较复杂的变量,的确是非常耗时并且消耗大的操作。(浪费指令时间、浪费内存)

    对于这样的函数返回:
    vector<string> str_split(const string& s) {
    vector<string> v;
    // ...
    return v; // v是左值,但优先移动,不支持移动时仍可复制。
    }

    标准要求先调用移动构造函数,如果不符合那么再调用拷贝构造函数。所以可以轻松地写出这种写法而不必担心效率问题。
    同时,现代编译器都会对返回值进行优化,成为RVO以及NRVO。所以不用太担心会多调用构造析构函数。

    对于完美转发,C++对于引用的转发有规则。传统的C++是无法对引用进行再引用的。但是现代的C++放宽了它的使用范围。
    只有右引用右值的时候,才会产生右引用。这也称为引用折叠。

    3、auto关键字的作用是什么?
    auto关键字为的是能够让编译器自动推导类型。自C++98之后,编译器对类型的推导变得越来越智能了。
    而我们在编写复杂代码的时候,冗长的类型不仅容易出错,有时也不容易人工推导出类型。
    因此auto可以简化我们的任务量,让类型的推导交给编译器完成。
    除了auto外,我们还可以使用decltype()来让编译器推导类型。

    read more
  • 我感觉比起《Physically Based Rendering Technique》,还是《Ray Tracing in a Weekend》更容易上手,因为慢慢地能够做出一个渲染效果,这个是有成就感的。🎓

    read more
  • G

    北京名律免费法律咨询,解决您的法律困扰,如果您眼下没有遇到法律上的问题,也可以留一位大律师的联系方式以备不时之需!ccfd91efc3a6b2ed0e79054d2248eed.jpg bf6015b383483f1fe83cdcfd130fc6b.jpg 2f347879129add1096bf3424edbe517.jpg

    read more

关注我们

微博
QQ群