我是靠谱客的博主 幸福唇膏,最近开发中收集的这篇文章主要介绍Qt源码分析之corelib,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

Qt源码解析

备注:使用vs2010编译的qt4.8.4版本。

1.corelib模块:

   首先我们来看QObject类,他是所有Qt对象的基类,也是Qt对象模型的中心。主要包括的功能有:信号和槽机制,事件和事件过滤器,国际化,定时器,对象结构树,对象销毁指针自动设置为0等。

我们来看看头文件:

Q_CORE_EXPORTvoid qt_qFindChildren_helper(const QObject *parent, const QString &name,const QRegExp *re,const QMetaObject &mo, QList<void *> *list);
Q_CORE_EXPORTQObject *qt_qFindChild_helper(const QObject *parent, const QString &name,const QMetaObject &mo);
定义了两个函数,主要是用来查找相关的子类。

看看实现:

void qt_qFindChildren_helper(const QObject *parent, const QString &name, constQRegExp *re,
                             const QMetaObject&mo, QList<void*> *list)
{
    if (!parent || !list)
        return;
    const QObjectList &children =parent->children(); //通过对象结构树进行循环查询子类
QObject*obj;
for(int i = 0; i < children.size(); ++i) {
obj= children.at(i);
if(mo.cast(obj)) {
if(re) {
if(re->indexIn(obj->objectName()) != -1)
list->append(obj);
}else {
if(name.isNull() || obj->objectName() == name)
list->append(obj);
}
}
qt_qFindChildren_helper(obj,name, re, mo, list);
    }
}

可以看出,返回 void helper 主要是通过父对象调用 children() 函数然后对子对象数组进行循环遍历,查找符合正则表达式的子类。

在这个两个函数的实现过程中运用了Qt metaObject 系统,我们以这两个函数的分析作为切入点来看看这个所谓的Qt metaObject系统。

这个系统主要基于的是三个方面的内容:QObject作为Qt系统的基类,提供了方便的一套完整的对象树系统;Q_OBJECT提供了QMataObject功能、信号槽、动态属性;moc编译器,为每个QObject子类动态生成相关的支持Qt metaObject代码。

我们从Q_OBJECT宏开始,可以说这是Qt得以构建的基础。

/*tmake ignore Q_OBJECT */
#defineQ_OBJECT 
public:
    Q_OBJECT_CHECK 
    static const QMetaObject staticMetaObject;  

    Q_OBJECT_GETSTATICMETAOBJECT 
    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 constQMetaObjectExtraData staticMetaObjectExtraData; 
    Q_DECL_HIDDEN static voidqt_static_metacall(QObject *, QMetaObject::Call, int, void **);
 
#defineQ_OBJECT_CHECK 
    template <typename T> inline voidqt_check_for_QOBJECT_macro(const T &_q_argument) const 
    { int i = qYouForgotTheQ_OBJECT_Macro(this,&_q_argument); i = i; }
template<typename T>
inlineint qYouForgotTheQ_OBJECT_Macro(T, T) { return 0; }
 
template<typename T1, typename T2>
inlinevoid qYouForgotTheQ_OBJECT_Macro(T1, T2) {}
 
 
#  define QT_TR_FUNCTIONS 
    static inline QString tr(const char *s,const char *c = 0) 
        { return staticMetaObject.tr(s, c); } 
    static inline QString trUtf8(const char *s,const char *c = 0) 
        { return staticMetaObject.trUtf8(s, c);} 
    static inline QString tr(const char *s,const char *c, int n) 
        { return staticMetaObject.tr(s, c, n);} 
    static inline QString trUtf8(const char *s,const char *c, int n) 
        { return staticMetaObject.trUtf8(s, c,n); }

这些宏的定义都在 qobjectdefs.h 文件中, Q_OBJECT_CHECK 其实就是没做什么工作,这个从

qYouForgotTheQ_OBJECT_Macro的两个模板函数的定义可以看出。但是不知道为什么要有i=i;这个句子,真心没什么用。

然后就是定义了类变量staticMetaObject,他是const型的,说明是不能改变的。我们来看看QMetaObject 源码,主要定义了

const char *className() const;//返回类名
const QMetaObject *superClass() const;//父对象的QMetaObject 指针
QObject *cast(QObject *obj) const;//转换函数
const QObject *cast(const QObject *obj)const;//国际化支持
QStringtr(const char *s, const char *c) const;
QStringtrUtf8(const char *s, const char *c) const;
QStringtr(const char *s, const char *c, int n) const;
QStringtrUtf8(const char *s, const char *c, int n) const;
 
   int methodOffset() const;                                 // 方法偏移量  
  int enumeratorOffset() const;                             // 枚举偏移量  
  int propertyOffset() const;                                   // 属性偏移量  
  int classInfoOffset() const;                                  // 类信息偏移量  
  int constructorCount() const;                             // 构造函数数目  
  int methodCount() const;                                  // 方法数目  
  int enumeratorCount() const;                              // 枚举数据  
  int propertyCount() const;                                    // 属性数目  
  int classInfoCount() const;                                   // 类信息数目  
  int indexOfConstructor(const char *constructor) const;            // 构函函数索引  
  int indexOfMethod(const char *method) const;                  // 方法索引  
  int indexOfSignal(const char *signal) const;                  // 信号量索引  
  int indexOfSlot(const char *slot) const;                      // 槽索引  
  int indexOfEnumerator(const char *name) const;                // 枚举索引  
  int indexOfProperty(const char *name) const;                  // 属性索引  
  int indexOfClassInfo(const char *name) const;                 // 类信息索引  
  QMetaMethod constructor(int index) const;                 // 构造方法  
  QMetaMethod method(int index) const;                      // 方法  
  QMetaEnum enumerator(int index) const;                        // 枚举  
  QMetaProperty property(int index) const;                      // 属性  
  QMetaClassInfo classInfo(int index) const;                    // 类属性信息      
  QMetaProperty userProperty() const;                           // 用户属性  
//一堆关于类的元数据。
 QMetaMethod constructor(int index) const;
    QMetaMethod method(int index) const;
    QMetaEnum enumerator(int index) const;
    QMetaProperty property(int index) const;
    QMetaClassInfo classInfo(int index) const;
    QMetaProperty userProperty() const;
 
    static bool checkConnectArgs(const char*signal, const char *method);
    static QByteArray normalizedSignature(constchar *method);
    static QByteArray normalizedType(const char*type);
 
    // internal index-based connect
    static bool connect(const QObject *sender,int signal_index,
                        const QObject*receiver, int method_index,
                        int type = 0, int*types = 0); //内部基于索引的connect
    // internal index-based disconnect
    static bool disconnect(const QObject*sender, int signal_index,
                           const QObject*receiver, int method_index);
    static bool disconnectOne(const QObject*sender, int signal_index,
                              const QObject*receiver, int method_index);
    // internal slot-name based connect
    static void connectSlotsByName(QObject *o);
 
    // internal index-based signal activation
    static void activate(QObject *sender, intsignal_index, void **argv);  //obsolete
    static void activate(QObject *sender, intfrom_signal_index, int to_signal_index, void **argv); //obsolete
    static void activate(QObject *sender, constQMetaObject *, int local_signal_index, void **argv);
    static void activate(QObject *sender, constQMetaObject *, int from_local_signal_index, int to_local_signal_index, void**argv); //obsolete
 
    // internal guarded pointers
    static void addGuard(QObject **ptr);
    static void removeGuard(QObject **ptr);
    static void changeGuard(QObject **ptr,QObject *o);
 
    static bool invokeMethod(QObject *obj,const char *member,
                            Qt::ConnectionType,
                            QGenericReturnArgument ret,
                             QGenericArgumentval0 = QGenericArgument(0),
                             QGenericArgumentval1 = QGenericArgument(),
                             QGenericArgumentval2 = QGenericArgument(),
                             QGenericArgumentval3 = QGenericArgument(),
                             QGenericArgumentval4 = QGenericArgument(),
                             QGenericArgumentval5 = QGenericArgument(),
                             QGenericArgumentval6 = QGenericArgument(),
                             QGenericArgumentval7 = QGenericArgument(),
                             QGenericArgumentval8 = QGenericArgument(),
                             QGenericArgumentval9 = QGenericArgument());
 
    static inline bool invokeMethod(QObject*obj, const char *member,
                            QGenericReturnArgument ret,
                             QGenericArgumentval0 = QGenericArgument(0),
                             QGenericArgumentval1 = QGenericArgument(),
                             QGenericArgumentval2 = QGenericArgument(),
                             QGenericArgumentval3 = QGenericArgument(),
                             QGenericArgumentval4 = QGenericArgument(),
                             QGenericArgumentval5 = QGenericArgument(),
                             QGenericArgumentval6 = QGenericArgument(),
                             QGenericArgumentval7 = QGenericArgument(),
                             QGenericArgumentval8 = QGenericArgument(),
                             QGenericArgumentval9 = QGenericArgument())
    {
        return invokeMethod(obj, member,Qt::AutoConnection, ret, val0, val1, val2, val3,
                val4, val5, val6, val7, val8,val9);
    }
 
    static inline bool invokeMethod(QObject*obj, const char *member,
                             Qt::ConnectionTypetype,
                             QGenericArgumentval0 = QGenericArgument(0),
                             QGenericArgumentval1 = QGenericArgument(),
                             QGenericArgumentval2 = QGenericArgument(),
                             QGenericArgumentval3 = QGenericArgument(),
                             QGenericArgumentval4 = QGenericArgument(),
                             QGenericArgumentval5 = QGenericArgument(),
                             QGenericArgumentval6 = QGenericArgument(),
                             QGenericArgumentval7 = QGenericArgument(),
                             QGenericArgumentval8 = QGenericArgument(),
                             QGenericArgumentval9 = QGenericArgument())
    {
        return invokeMethod(obj, member, type,QGenericReturnArgument(), val0, val1, val2,
                                 val3, val4,val5, val6, val7, val8, val9);
    }
 
    static inline bool invokeMethod(QObject*obj, const char *member,
                             QGenericArgumentval0 = QGenericArgument(0),
                             QGenericArgumentval1 = QGenericArgument(),
                             QGenericArgumentval2 = QGenericArgument(),
                             QGenericArgumentval3 = QGenericArgument(),
                             QGenericArgumentval4 = QGenericArgument(),
                             QGenericArgumentval5 = QGenericArgument(),
                             QGenericArgumentval6 = QGenericArgument(),
                             QGenericArgumentval7 = QGenericArgument(),
                             QGenericArgumentval8 = QGenericArgument(),
                             QGenericArgumentval9 = QGenericArgument())
    {
        return invokeMethod(obj, member,Qt::AutoConnection, QGenericReturnArgument(), val0,
                val1, val2, val3, val4, val5,val6, val7, val8, val9);
    }
 
    QObject *newInstance(QGenericArgument val0= QGenericArgument(0),
                         QGenericArgument val1= QGenericArgument(),
                         QGenericArgument val2= QGenericArgument(),
                         QGenericArgument val3= QGenericArgument(),
                         QGenericArgument val4= QGenericArgument(),
                         QGenericArgument val5= QGenericArgument(),
                         QGenericArgument val6= QGenericArgument(),
                         QGenericArgument val7= QGenericArgument(),
                         QGenericArgument val8= QGenericArgument(),
                         QGenericArgument val9= QGenericArgument()) const;
 
    enum Call {
        InvokeMetaMethod,
        ReadProperty,
        WriteProperty,
        ResetProperty,
        QueryPropertyDesignable,
        QueryPropertyScriptable,
        QueryPropertyStored,
        QueryPropertyEditable,
        QueryPropertyUser,
        CreateInstance
    };
 
    int static_metacall(Call, int, void **)const;
    static int metacall(QObject *, Call, int,void **);
 
#ifdefQT3_SUPPORT
   QT3_SUPPORT const char *superClassName() const; //父类名称
#endif
 
    struct { // private data
        const QMetaObject *superdata;
        const char *stringdata;
        const uint *data;
        const void *extradata;
   } d; //关于类信息的私有数据,包括父类的QMetaObject 指针,类的名称和基于uint指针类型的数据,还有一些其他类型的额外数据。在这里d.data一般是
QMetaObjectPrivate对象的指针,这个可以在对QMetaObjectPrivate结构源码分析的时候可以得到解释。
 
};
 
在这里不得不说说Qt的私有数据存储,在c++编程中,类的成员变量通常做法是在类定义过程中直接定义的,但是Qt却是用了一种比较不同的方式,他是通过一个指针指向一个数据的成员对象,这个数据的成员对象包含着这个类的所有成员数据。这样做有他的优点,比如因为一般包含成员对象的结构都是在cpp文件中定义的,这样一旦发生修改,就不用修改头文件,减少了头文件的依赖,同时增强了封装性
typedefconst QMetaObject& (*QMetaObjectAccessor)();
 
structQMetaObjectExtraData
{
#ifdefQ_NO_DATA_RELOCATION
    const QMetaObjectAccessor *objects;
#else
    const QMetaObject **objects;
#endif
 
    typedef void(*StaticMetacallFunction)(QObject *, QMetaObject::Call, int, void **); //fromrevision 6
    //typedef int(*StaticMetaCall)(QMetaObject::Call, int, void **); //used from revison 2 untilrevison 5
    StaticMetacallFunction static_metacall;
};
 
inlineconst char *QMetaObject::className() const
{return d.stringdata; }
 
inlineconst QMetaObject *QMetaObject::superClass() const
{return d.superdata; }
 
#ifdefQT3_SUPPORT
inlineconst char *QMetaObject::superClassName() const
{return d.superdata ? d.superdata->className() : 0; }
#endif
 
QT_END_NAMESPACE
 
QT_END_HEADER
 
#endif// QOBJECTDEFS_H
 
QMetaObjectPrivate结构:
structQMetaObjectPrivate
{
   int revision;  //版本
   int className;//类名
    int classInfoCount, classInfoData;
    int methodCount, methodData;
    int propertyCount, propertyData;
    int enumeratorCount, enumeratorData;
    int constructorCount, constructorData;//since revision 2
    int flags; //since revision 3
    int signalCount; //since revision 4
    // revision 5 introduces changes innormalized signatures, no new members
    // revision 6 added qt_static_metacall as amember of each Q_OBJECT and inside QMetaObject itself
 
    static inline const QMetaObjectPrivate*get(const QMetaObject *metaobject)
   { return reinterpret_cast<constQMetaObjectPrivate*>(metaobject->d.data); }//通过这个函数,可以看出在QMetaObject类中的d结构中的uint指针指向的是一个QMetaObjectPrivate结构,通过这个指针 QMetaObject 可以获得自己的私有数据。
 
    static int indexOfSignalRelative(constQMetaObject **baseObject,
                                     constchar* name,
                                     boolnormalizeStringData);
    static int indexOfSlotRelative(constQMetaObject **m,
                           const char *slot,
                           boolnormalizeStringData);
    static int originalClone(const QMetaObject*obj, int local_method_index);
 
#ifndefQT_NO_QOBJECT
    //defined in qobject.cpp
    enum DisconnectType { DisconnectAll,DisconnectOne };
    static void memberIndexes(const QObject*obj, const QMetaMethod &member,
                              int *signalIndex,int *methodIndex);
    static bool connect(const QObject *sender,int signal_index,
                        const QObject*receiver, int method_index_relative,
                        const QMetaObject*rmeta = 0,
                        int type = 0, int*types = 0);
    static bool disconnect(const QObject*sender, int signal_index,
                           const QObject*receiver, int method_index,
                           DisconnectType =DisconnectAll);
    static inline booldisconnectHelper(QObjectPrivate::Connection *c,
                                        constQObject *receiver, int method_index,
                                        QMutex*senderMutex, DisconnectType);
#endif
};
 
#ifndefUTILS_H
//mirrored in moc's utils.h
staticinline bool is_ident_char(char s)
{
    return ((s >= 'a' && s <='z')
            || (s >= 'A' && s <='Z')
            || (s >= '0' && s <='9')
            || s == '_'
       );
}
 
staticinline bool is_space(char s)
{
    return (s == ' ' || s == 't');
}
#endif
 
//This code is shared with moc.cpp
staticQByteArray normalizeTypeInternal(const char *t, const char *e, bool fixScope =false, bool adjustConst = true)
{
    int len = e - t;
    /*
      Convert 'char const *' into 'const char*'. Start at index 1,
      not 0, because 'const char *' is alreadyOK.
    */
    QByteArray constbuf;
    for (int i = 1; i < len; i++) {
        if ( t[i] == 'c'
             && strncmp(t + i + 1,"onst", 4) == 0
             && (i + 5 >= len ||!is_ident_char(t[i + 5]))
             && !is_ident_char(t[i-1])
             ) {
            constbuf = QByteArray(t, len);
            if (is_space(t[i-1]))
                constbuf.remove(i-1, 6);
            else
                constbuf.remove(i, 5);
            constbuf.prepend("const");
            t = constbuf.data();
            e = constbuf.data() +constbuf.length();
            break;
        }
        /*
          We musn't convert 'char * const *'into 'const char **'
          and we must beware of 'Bar<constBla>'.
        */
        if (t[i] == '&' || t[i] == '*'||t[i] == '<')
            break;
    }
    if (adjustConst && e > t + 6&& strncmp("const ", t, 6) == 0) {
        if (*(e-1) == '&') { // treat constreference as value
            t += 6;
            --e;
        } else if (is_ident_char(*(e-1)) ||*(e-1) == '>') { // treat const value as value
            t += 6;
        }
    }
    QByteArray result;
    result.reserve(len);
 
#if1
    // consume initial 'const '
    if (strncmp("const ", t, 6) == 0){
        t+= 6;
        result += "const ";
    }
#endif
 
    // some type substitutions for 'unsigned x'
    if (strncmp("unsigned", t, 8) ==0) {
        // make sure "unsigned" is anisolated word before making substitutions
        if (!t[8] || !is_ident_char(t[8])) {
            if (strncmp(" int", t+8,4) == 0) {
                t += 8+4;
                result += "uint";
            } else if (strncmp("long", t+8, 5) == 0) {
                if ((strlen(t + 8 + 5) < 4|| strncmp(t + 8 + 5, " int", 4) != 0) // preserve '[unsigned] longint'
                    && (strlen(t + 8 +5) < 5 || strncmp(t + 8 + 5, " long", 5) != 0) // preserve'[unsigned] long long'
                   ) {
                    t += 8+5;
                    result +="ulong";
                }
            } else if (strncmp("short", t+8, 6) != 0  // preserveunsigned short
                && strncmp("char", t+8, 5) != 0) {    //preserve unsigned char
                //  treat rest (unsigned) as uint
                t += 8;
                result += "uint";
            }
        }
    } else {
        // discard 'struct', 'class', and'enum'; they are optional
        // and we don't want them in thenormalized signature
        struct {
            const char *keyword;
            int len;
        } optional[] = {
            { "struct ", 7 },
            { "class ", 6 },
            { "enum ", 5 },
            { 0, 0 }
        };
        int i = 0;
        do {
            if (strncmp(optional[i].keyword, t,optional[i].len) == 0) {
                t += optional[i].len;
                break;
            }
        } while (optional[++i].keyword != 0);
    }
 
    bool star = false;
    while (t != e) {
        char c = *t++;
        if (fixScope && c == ':'&& *t == ':' ) {
            ++t;
            c = *t++;
            int i = result.size() - 1;
            while (i >= 0 &&is_ident_char(result.at(i)))
                --i;
            result.resize(i + 1);
        }
        star = star || c == '*';
        result += c;
        if (c == '<') {
            //template recursion
            const char* tt = t;
            int templdepth = 1;
            while (t != e) {
                c = *t++;
                if (c == '<')
                    ++templdepth;
                if (c == '>')
                    --templdepth;
                if (templdepth == 0 ||(templdepth == 1 && c == ',')) {
                    result +=normalizeTypeInternal(tt, t-1, fixScope, false);
                    result += c;
                    if (templdepth == 0) {
                        if (*t == '>')
                            result += ' '; //avoid >>
                        break;
                    }
                    tt = t;
                }
            }
        }
 
        // cv qualifers can appear after thetype as well
        if (!is_ident_char(c) && t != e&& (e - t >= 5 && strncmp("const", t, 5) == 0)
            && (e - t == 5 ||!is_ident_char(t[5]))) {
            t += 5;
            while (t != e &&is_space(*t))
                ++t;
            if (adjustConst && t != e&& *t == '&') {
                // treat const ref as value
                ++t;
            } else if (adjustConst &&!star) {
                // treat const as value
            } else if (!star) {
                // move const to the front (butnot if const comes after a *)
                result.prepend("const");
            } else {
                // keep const after a *
                result += "const";
            }
        }
    }
 
    return result;
}

   作为 QMetaObject 类的私有数据结构, QMetaObject 可以通过这个数据结构获得关于类的很多信息。 QMetaMethod Q MetaEnum QMetaProperty QMetaClassInfo 几个类都要通过 QMetaObject QMetaObjectPrivate 类获取相关信息,这些类 的解析见下面。

QMetaObject.cpp文件:

staticinline const QMetaObjectPrivate *priv(const uint* data)

{ return reinterpret_cast<constQMetaObjectPrivate*>(data); }//通过d.data转换成QMetaObjectPrivate类型。

 

QObject *QMetaObject::newInstance...//返回该类的实例,主要调用的是

static_metacall(CreateInstance, idx,param) 这个函数,这个函数的作用是先判断类版本,如果版本大于等于6则调用d结构中的QMetaObjectExtraData中的static_metacall,static_metacall其实就是一个typedef void (*StaticMetacallFunction)(QObject *, QMetaObject::Call,int, void **)函数指针。如果版本大于等于2则要进行函数指针的转换,然后进行调用。

 

QObject*QMetaObject::cast(QObject *obj) const
{
if(obj) {
constQMetaObject *m = obj->metaObject();
do{
if(m == this)
returnobj;
}while ((m = m->d.superdata));
}
return0;
}//查看obj所指向的对象是否在该类的继承栈中,主要通过不断调用d.superdata向上返回父对象进行判断。
 
*/
QStringQMetaObject::tr(const char *s, const char *c, int n) const
{
    returnQCoreApplication::translate(d.stringdata, s, c, QCoreApplication::CodecForTr,n);
}
 
/*!
    internal
*/
QStringQMetaObject::trUtf8(const char *s, const char *c) const
{
    returnQCoreApplication::translate(d.stringdata, s, c, QCoreApplication::UnicodeUTF8);
}
 
/*!
    internal
*/
QStringQMetaObject::trUtf8(const char *s, const char *c, int n) const
{
    returnQCoreApplication::translate(d.stringdata, s, c, QCoreApplication::UnicodeUTF8,n);
}
#endif
QMetaObject中的国际化支持主要是通过调用QCoreApplication类中的方法实现。
 
intQMetaObject::methodOffset() const
{
intoffset = 0;
constQMetaObject *m = d.superdata;
while(m) {
offset+= priv(m->d.data)->methodCount;
m= m->d.superdata;
}
returnoffset;
}//这个offset主要是沿继承体系向上统计类方法数量,里子类越远的父类offset越大。
 
intQMetaObject::enumeratorOffset() const
{
    int offset = 0;
    const QMetaObject *m = d.superdata;
    while (m) {
        offset +=priv(m->d.data)->enumeratorCount;
        m = m->d.superdata;
    }
    return offset;
}//使用的手法同上。
 
intQMetaObject::propertyOffset() const
{
    int offset = 0;
    const QMetaObject *m = d.superdata;
    while (m) {
        offset +=priv(m->d.data)->propertyCount;
        m = m->d.superdata;
    }
    return offset;
}//同上
…
待续


最后

以上就是幸福唇膏为你收集整理的Qt源码分析之corelib的全部内容,希望文章能够帮你解决Qt源码分析之corelib所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(35)

评论列表共有 0 条评论

立即
投稿
返回
顶部