转载自:https://blog.csdn.net/weixin_39955229/article/details/81901603
原文标题:QObject多继承static_meta_object的编译问题
问题描述
继承一个类,再继承自QObject并添加Q_OBJECT的宏之后,编译不过。
class A{public:
A(){};
~A(){};
private:
int m_aval;
};
class DerivedObject : public A,public QObject
{
Q_OBJECT
public:
DerivedObject();
~DerivedObject();
private:
int m_dval;
};
错误信息:
错误 1 error C2039: “staticMetaObject”: 不是“A”的成员 c:\Users\chuan\documents\visual studio 2010\Projects\DerivedObject\DerivedObject\GeneratedFiles\Debug\moc_derivedobject.cpp 53 DerivedObject
错误 2 error C2039: “qt_metacast”: 不是“A”的成员 c:\Users\chuan\documents\visual studio 2010\Projects\DerivedObject\DerivedObject\GeneratedFiles\Debug\moc_derivedobject.cpp 73 DerivedObject
错误 3 error C2039: “qt_metacall”: 不是“A”的成员 c:\Users\chuan\documents\visual studio 2010\Projects\DerivedObject\DerivedObject\GeneratedFiles\Debug\moc_derivedobject.cpp 78 DerivedObject
问题分析
首先,我们尝试输出该类的内存布局,分析错误原因。
vs下右键属性
->配置属性
->C/C++
->命令行
,在下方其他选项中填入:
/d1 reportSingleClassLayout**DerivedObject**
加粗部分是具体的类名,表示输出哪个类的内存布局情况,可以自定义,我这里用的类名是 DerivedObject。
设置完保存,直接编译,
+---
| +--- (base class QObject)
0 | | {vfptr}
4 | | ?$QScopedPointer@VQObjectData@@U?$QScopedPointerDeleter@VQObjectData@@@@ d_ptr
| +---
| +--- (base class A)
8 | | m_aval
| +---
12 | m_dval
+---
DerivedObject::$vftable@:
| &DerivedObject_meta
| 0
0 | &DerivedObject::metaObject
1 | &DerivedObject::qt_metacast
2 | &DerivedObject::qt_metacall
3 | &DerivedObject::{dtor}
4 | &QObject::event
5 | &QObject::eventFilter
6 | &QObject::timerEvent
7 | &QObject::childEvent
8 | &QObject::customEvent
9 | &QObject::connectNotify
10 | &QObject::disconnectNotify
DerivedObject::metaObject this adjustor: 0
DerivedObject::qt_metacast this adjustor: 0
DerivedObject::qt_metacall this adjustor: 0
DerivedObject::{dtor} this adjustor: 0
DerivedObject::__delDtor this adjustor: 0
DerivedObject::__vecDelDtor this adjustor: 0
注意这里虚函数表的展开,有几个虚函数地址。但是我们并没有在DerivedObject中重写任何虚函数,那么这个虚函数表的布局为什么是这样的呢?
注意类定义的开始,加入了一个宏Q_OBJECT,进入定义发现:
#define Q_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 const QMetaObjectExtraData staticMetaObjectExtraData; \
Q_DECL_HIDDEN static void qt_static_metacall(QObject *, QMetaObject::Call, int, void **);
也就是说,只要包含了Q_OBJECT着个宏,它就会在编译的时候展开为一堆定义和重写的虚函数,然后在MOC的时候在CPP中加入定义。比如此时对应的moc_derivedobject.cpp里编译器自己加上的导致出错的地方:
const QMetaObject DerivedObject::staticMetaObject = {
{ &A::staticMetaObject, qt_meta_stringdata_DerivedObject,
qt_meta_data_DerivedObject, &staticMetaObjectExtraData }
};
注意第一个参数 &A::staticMetaObject
,我们自己定义的类A是没有staticMetaObject着个成员的,这是QObject的宏展开之后才有的定义。此时如果把DerivedObject继承顺序更改一下:
class DerivedObject : public A,public QObject
其他部分保持不变,然后编译并输出:
const QMetaObject DerivedObject::staticMetaObject = {
{ &QObject::staticMetaObject, qt_meta_stringdata_DerivedObject,
qt_meta_data_DerivedObject, &staticMetaObjectExtraData }
};
编译通过: }。
输出内存布局A和QObject的只是顺序对换,因为DerivedObject继承自A和QObject的关系没有改变,即使顺序改变,Q_OBJECT宏只有一个static变量不占类的内存。