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); }}
可以看出,返回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_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可以通过这个数据结构获得关于类的很多信息。QMetaMethod、QMetaEnum、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);}#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;}//同上…
待续
- Qt源码分析之corelib
- Qt 源码学习日志 - corelib->kernel->qmath
- Qt源码分析之QObject
- Qt源码分析之QPointer
- Qt源码分析之QObject
- Qt源码分析之QObject
- Qt源码分析之QPointer
- Qt源码分析之QObject
- Qt源码分析之QObject
- Qt源码分析之QObject
- Qt源码分析之QObject
- Qt源码分析之QPointer
- Qt源码分析之QObject
- Qt源码分析之QPointer
- Qt源码分析之QObject
- Qt源码分析之QObject
- Qt源码分析之QObject
- Qt源码分析之QObject (转)
- 为什么说AWT是重量级控件,而Swing是轻量级控件?
- JavaScript之appendChild、insertBefore和insertAfter使用说明
- 数据库性能优化深入浅析
- Zero Clipboard js+swf实现的复制功能使用方法
- 分数类
- Qt源码分析之corelib
- oracle的分析函数学习
- All about Oracle FED and KFOD tools
- G - dp-easy
- 快速排序算法
- Android网络连接判断与处理
- Python - 开始使用Python编程
- C++。NET的代码学习资料,真是少啊
- 高效Linux用户需要了解的命令行技能