概述
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所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复