[QT]moc生成文件分析
2011-09-26 16:22
316 查看
首先看一下简单含有的signal, slot代码
view
plain
class myClass : public QObject
{
Q_OBJECT
public:
myClass();
~myClass();
void trigger();
void trigger2();
signals:
void signalFunc(double);
int signalFunc2(char, int);
protected slots:
void slotFunc(double);
int slotFunc2(char);
};
// 只是实例代码,用来生成moc_myClass
#include"myClass.h"
#include<iostream>
using std::cout;
using std::endl;
myClass::myClass()
{
connect(this, SIGNAL(signalFunc),
this, SLOT(slotFunc));
connect(this, SIGNAL(signalFunc2),
this, SLOT(slotFunc2));
}
myClass::~myClass()
{
}
void myClass::slotFunc(double d)
{
cout << "slotFunc" << endl;
}
int myClass::slotFunc2(char c)
{
cout << "slotFunc2" << endl;
return c;
}
void myClass::trigger()
{
}
void myClass::trigger2()
{
}
编译生成moc_myClass.cpp
view
plain
static const uint qt_meta_data_myClass[] = {
// content:
4, // revision
0, // classname
0, 0, // classinfo
4, 14, // methods
0, 0, // properties
0, 0, // enums/sets
0, 0, // constructors
0, // flags
2, // signalCount
// signals: signature, parameters, type, tag, flags
9, 8, 8, 8, 0x05,
34, 32, 28, 8, 0x05,
// slots: signature, parameters, type, tag, flags
56, 8, 8, 8, 0x09,
73, 8, 28, 8, 0x09,
0 // eod
};
其中methods部分,4代表这个对象含有4个signal + slot, 14是基础数字,在moc代码里面也是硬编码,数一下content的个数,刚好是14,这个14其实就是个偏移量,偏移到signal的第一行
signal和slot的flag提供了一些属性,这个会在后面的QObject::connect讲到。
这里需要提出来一点是signal和slot的第一个数值,9, 34, 56, 73这几个,这个马上会讲到先提出来,留个印象
这里前14个数值是对应的QMetaObjectPrivate的值
view
plain
struct QMetaObjectPrivate
{
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
...
...
}
接下来是
view
plain
static const char qt_meta_stringdata_myClass[] = {
"myClass/0/0signalFunc(double)/0int/0,/0"
"signalFunc2(char,int)/0slotFunc(double)/0"
"slotFunc2(char)/0"
};
从这个字符串里面,可以看到第一个值为这个类的类名(元对象可以不通过RTTI给出类名的原因就在这里)
在第一个/0后面会给出第一个signal的返回值类型,在这个例子中signalFunc没有返回值,所以没有任何内容,
在第二个/0后面会给出参数名,因为moc读取的是头文件,而我们在头文件中没定义参数名,所以为空
然后就是signal的名字和参数列表类型,这里需要注意的是,即使头文件给出了参数名,在这里也会被忽略掉,只提供类型
再下一个/0后面就是下一个函数的描述了,描述的方式跟前面是一样的。
刚刚提到的9, 34, 56, 73这几个数字,在这里是有用的,这几个数字,刚好是这个字符串对应的函数开头的部分。比如9,那我们在这个字符串中数9个字符,即signalFunc(double)这一段内容。
然后是源对象的数据定义:
view
plain
const QMetaObject myClass::staticMetaObject = {
{ &QObject::staticMetaObject, qt_meta_stringdata_myClass,
qt_meta_data_myClass, 0 }
};
可以看到源对象的数据定义为:
struct { // private data
const QMetaObject *superdata;
const char *stringdata;
const uint *data;
const void *extradata;
}
这个名为staticMetaObject的对象是由Q_OBJECT引入的
第一个数据为父类名字, moc对于多继承的限制可能也在于此。
moc规定多继承的情况下,moc会假设第一个继承的类为QObject, 并且必须要保证在多继承中,只有唯一一个类是继承自QObject的。这样看上去,多余一个QObject继承的,第二个QObject根本没办法识别出来。
第二个数据就是上面的字符串数据
第三个也是上面的uint*数据。
这个源对象非常关键,后面的内容就靠他了。
view
plain
const QMetaObject &myClass::getStaticMetaObject() { return staticMetaObject; }
const QMetaObject *myClass::metaObject() const
{
return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;
}
这2个方法都是由Q_OBJECT引入的。目的是返回这个类的元对象
view
plain
void *myClass::qt_metacast(const char *_clname)
{
if (!_clname) return 0;
if (!strcmp(_clname, qt_meta_stringdata_myClass))
return static_cast<void*>(const_cast< myClass*>(this));
return QObject::qt_metacast(_clname);
}
还是由Q_OBJECT引入的
当传入的字符串数据是当前这个类的话,就将this指针转换成void指针传给外界: 这个操作相当危险。
如果不是当前类的话,就调用父类的qt_metacast继续查询。
在这里,我的父类是QObject,所以自然就调用QObject::qt_metacase了
在看qt_metacall之前,先看下signal的定义。 额。。事实上signal不需要你自己定义,moc已经帮我们完成这点了。
具体内容如下:
view
plain
// SIGNAL 0
void myClass::signalFunc(double _t1)
{
void *_a[] = { 0, const_cast<void*>(reinterpret_cast<const void*>(&_t1)) };
QMetaObject::activate(this, &staticMetaObject, 0, _a);
}
我们看到他将所有的参数都转型成void*指针保存到 void *a的数组中,然后调用了
QMetaObject::activate(this, &staticMetaObject, 0, _a);
看到传入的参数为this, 源对象和参数
这个函数实际上就是触发消息的函数,在这里不过多关注他,有机会再写
最终,int myClass::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
会被调用,用来处理对应的signal的消息
代码如下
view
plain
int myClass::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
{
_id = QObject::qt_metacall(_c, _id, _a);
if (_id < 0)
return _id;
if (_c == QMetaObject::InvokeMetaMethod) {
switch (_id) {
case 0: signalFunc((*reinterpret_cast< double(*)>(_a[1]))); break;
case 1: { int _r = signalFunc2((*reinterpret_cast< char(*)>(_a[1])),(*reinterpret_cast< int(*)>(_a[2])));
if (_a[0]) *reinterpret_cast< int*>(_a[0]) = _r; } break;
case 2: slotFunc((*reinterpret_cast< double(*)>(_a[1]))); break;
case 3: { int _r = slotFunc2((*reinterpret_cast< char(*)>(_a[1])));
if (_a[0]) *reinterpret_cast< int*>(_a[0]) = _r; } break;
default: ;
}
_id -= 4;
}
return _id;
}
这里可以注意下,有返回值和没有返回值的处理方法~
moc所作的这些工作,都是为了元对象能更好的工作而做的准备
view
plain
class myClass : public QObject
{
Q_OBJECT
public:
myClass();
~myClass();
void trigger();
void trigger2();
signals:
void signalFunc(double);
int signalFunc2(char, int);
protected slots:
void slotFunc(double);
int slotFunc2(char);
};
// 只是实例代码,用来生成moc_myClass
#include"myClass.h"
#include<iostream>
using std::cout;
using std::endl;
myClass::myClass()
{
connect(this, SIGNAL(signalFunc),
this, SLOT(slotFunc));
connect(this, SIGNAL(signalFunc2),
this, SLOT(slotFunc2));
}
myClass::~myClass()
{
}
void myClass::slotFunc(double d)
{
cout << "slotFunc" << endl;
}
int myClass::slotFunc2(char c)
{
cout << "slotFunc2" << endl;
return c;
}
void myClass::trigger()
{
}
void myClass::trigger2()
{
}
编译生成moc_myClass.cpp
view
plain
static const uint qt_meta_data_myClass[] = {
// content:
4, // revision
0, // classname
0, 0, // classinfo
4, 14, // methods
0, 0, // properties
0, 0, // enums/sets
0, 0, // constructors
0, // flags
2, // signalCount
// signals: signature, parameters, type, tag, flags
9, 8, 8, 8, 0x05,
34, 32, 28, 8, 0x05,
// slots: signature, parameters, type, tag, flags
56, 8, 8, 8, 0x09,
73, 8, 28, 8, 0x09,
0 // eod
};
其中methods部分,4代表这个对象含有4个signal + slot, 14是基础数字,在moc代码里面也是硬编码,数一下content的个数,刚好是14,这个14其实就是个偏移量,偏移到signal的第一行
signal和slot的flag提供了一些属性,这个会在后面的QObject::connect讲到。
这里需要提出来一点是signal和slot的第一个数值,9, 34, 56, 73这几个,这个马上会讲到先提出来,留个印象
这里前14个数值是对应的QMetaObjectPrivate的值
view
plain
struct QMetaObjectPrivate
{
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
...
...
}
接下来是
view
plain
static const char qt_meta_stringdata_myClass[] = {
"myClass/0/0signalFunc(double)/0int/0,/0"
"signalFunc2(char,int)/0slotFunc(double)/0"
"slotFunc2(char)/0"
};
从这个字符串里面,可以看到第一个值为这个类的类名(元对象可以不通过RTTI给出类名的原因就在这里)
在第一个/0后面会给出第一个signal的返回值类型,在这个例子中signalFunc没有返回值,所以没有任何内容,
在第二个/0后面会给出参数名,因为moc读取的是头文件,而我们在头文件中没定义参数名,所以为空
然后就是signal的名字和参数列表类型,这里需要注意的是,即使头文件给出了参数名,在这里也会被忽略掉,只提供类型
再下一个/0后面就是下一个函数的描述了,描述的方式跟前面是一样的。
刚刚提到的9, 34, 56, 73这几个数字,在这里是有用的,这几个数字,刚好是这个字符串对应的函数开头的部分。比如9,那我们在这个字符串中数9个字符,即signalFunc(double)这一段内容。
然后是源对象的数据定义:
view
plain
const QMetaObject myClass::staticMetaObject = {
{ &QObject::staticMetaObject, qt_meta_stringdata_myClass,
qt_meta_data_myClass, 0 }
};
可以看到源对象的数据定义为:
struct { // private data
const QMetaObject *superdata;
const char *stringdata;
const uint *data;
const void *extradata;
}
这个名为staticMetaObject的对象是由Q_OBJECT引入的
第一个数据为父类名字, moc对于多继承的限制可能也在于此。
moc规定多继承的情况下,moc会假设第一个继承的类为QObject, 并且必须要保证在多继承中,只有唯一一个类是继承自QObject的。这样看上去,多余一个QObject继承的,第二个QObject根本没办法识别出来。
第二个数据就是上面的字符串数据
第三个也是上面的uint*数据。
这个源对象非常关键,后面的内容就靠他了。
view
plain
const QMetaObject &myClass::getStaticMetaObject() { return staticMetaObject; }
const QMetaObject *myClass::metaObject() const
{
return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;
}
这2个方法都是由Q_OBJECT引入的。目的是返回这个类的元对象
view
plain
void *myClass::qt_metacast(const char *_clname)
{
if (!_clname) return 0;
if (!strcmp(_clname, qt_meta_stringdata_myClass))
return static_cast<void*>(const_cast< myClass*>(this));
return QObject::qt_metacast(_clname);
}
还是由Q_OBJECT引入的
当传入的字符串数据是当前这个类的话,就将this指针转换成void指针传给外界: 这个操作相当危险。
如果不是当前类的话,就调用父类的qt_metacast继续查询。
在这里,我的父类是QObject,所以自然就调用QObject::qt_metacase了
在看qt_metacall之前,先看下signal的定义。 额。。事实上signal不需要你自己定义,moc已经帮我们完成这点了。
具体内容如下:
view
plain
// SIGNAL 0
void myClass::signalFunc(double _t1)
{
void *_a[] = { 0, const_cast<void*>(reinterpret_cast<const void*>(&_t1)) };
QMetaObject::activate(this, &staticMetaObject, 0, _a);
}
我们看到他将所有的参数都转型成void*指针保存到 void *a的数组中,然后调用了
QMetaObject::activate(this, &staticMetaObject, 0, _a);
看到传入的参数为this, 源对象和参数
这个函数实际上就是触发消息的函数,在这里不过多关注他,有机会再写
最终,int myClass::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
会被调用,用来处理对应的signal的消息
代码如下
view
plain
int myClass::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
{
_id = QObject::qt_metacall(_c, _id, _a);
if (_id < 0)
return _id;
if (_c == QMetaObject::InvokeMetaMethod) {
switch (_id) {
case 0: signalFunc((*reinterpret_cast< double(*)>(_a[1]))); break;
case 1: { int _r = signalFunc2((*reinterpret_cast< char(*)>(_a[1])),(*reinterpret_cast< int(*)>(_a[2])));
if (_a[0]) *reinterpret_cast< int*>(_a[0]) = _r; } break;
case 2: slotFunc((*reinterpret_cast< double(*)>(_a[1]))); break;
case 3: { int _r = slotFunc2((*reinterpret_cast< char(*)>(_a[1])));
if (_a[0]) *reinterpret_cast< int*>(_a[0]) = _r; } break;
default: ;
}
_id -= 4;
}
return _id;
}
这里可以注意下,有返回值和没有返回值的处理方法~
moc所作的这些工作,都是为了元对象能更好的工作而做的准备
相关文章推荐
- [QT]moc生成文件分析
- [QT]moc生成文件分析
- VS下QT工程不能生成moc文件的解决方法
- Qt工程没有对应生成moc文件
- vs2010中moc文件生成方法,qt找不到moc_**.cpp
- Qt 手动生成moc 文件
- vs2010中自动生成Qt的moc文件的方法
- qt-vs2010 手动添加新的qt类时,无法生成moc文件的解决
- vs中结合Qt的UI文件生成moc文件的方法
- Qt自动生成moc文件
- 手动生成Qt的moc文件的方法
- VS+QT混合编程中 自动生成Qt的moc文件的方法
- VS 下Qt工程不能生成moc文件的解决方法
- qt 手动生成moc 文件
- Const变量和enum变量gcc编译生成目标文件分析
- 基于TCP网络通信的自动升级程序源码分析--生成升级文件相关的配置文件
- C/C++程序从编译到最终生成可执行文件的过程分析
- 分析两种Dump(崩溃日志)文件生成的方法及比较
- Qt生成动/静态链接库的*.pro文件设置
- 【phpcms-v9】content_form.calss.php文件分析-内容添加页面动态表单的生成原理