Qt源码分析之corelib

来源:互联网 发布:java中时间格式化 编辑:程序博客网 时间:2024/05/01 05:00

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);    }}

可以看出,返回voidhelper主要是通过父对象调用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_SUPPORTinlineconst 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.hstaticinline 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.cppstaticQByteArray 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可以通过这个数据结构获得关于类的很多信息。QMetaMethodQMetaEnumQMetaPropertyQMetaClassInfo几个类都要通过QMetaObjectQMetaObjectPrivate类获取相关信息,这些类的解析见下面。

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);}#endifQMetaObject中的国际化支持主要是通过调用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;}//同上…
待续