天天看點

error C2039: “staticMetaObject”: 不是“A”的成員 c:\Users\chuan\documents\visual studio 2010\Projects\Deriv

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

以上,繼承QObject并加入Q_OBJECT宏的時候,QT環境下在編譯的時候會以第一個繼承的對象(模闆?)來生成對應的moc檔案,如果帶有Q_OBJECT宏,必須把QObject放在第一個繼承的位置。