原文标題: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 }
};