無意中發現在Qt的文檔里有一篇關于moc工具的limitation的文章,里頭的東西值得學習一下。
Qt一個鏈接的錯誤, 程序結構很簡單, 就是designer設計主界面,在代碼里用多重繼承方式使用, 奇怪的錯誤信息如下:
moc_mainwin.cpp:39: error: ‘staticMetaObject’ is not a member of ‘Ui::MainWindow’
moc_mainwin.cpp: In member function ‘virtual void* MainWin::qt_metacast(const char)’: moc_mainwin.cpp:56: error: ‘qt_metacast’ is not a member of ‘MainWin::qt_metacast(const char)::QMocSuperClass’
moc_mainwin.cpp: In member function ‘virtual int MainWin::qt_metacall(QMetaObject::Call, int, void)’: moc_mainwin.cpp:62: error: ‘qt_metacall’ is not a member of ‘MainWin::qt_metacall(QMetaObject::Call, int, void)::QMocSuperClass’
make: *** [moc_mainwin.o] Error 1
Qt自動生成的moc文件竟然也會編譯出錯?這可真有點匪夷所思。把工程拿過來從頭看到尾也沒有看出任何錯誤可能會導致這個鏈接錯誤。 N長時間后,一個編譯階段報出的warning引起了我的注意, 大意是說多重繼承不能從兩個QObject類繼承, 這就怪了,它怎么會把我的UI類也當成是從QObject派生的呢? 有了這個提示,嘗試著修改多重繼承的那行代碼:
class MainWin: public Ui::MainWindow, public QWidget
改為
class MainWin: public QWidget, public Ui::MainWindow
結果你猜怎么著?奇跡發生了……呵呵,編譯成功!原來竟然是繼承的順序造成的問題。 莫非這是Qt的bug?
給trolltech support發bug report得到了這樣的回答:
This is actually a known limitation which has been documented for some time, when using multiple inheritance you have to specify the QObject based class first and then the other class. Its mentioned in the documentation at:
http://doc.trolltech.com/4.5/moc.html
under the limitations section.
原來如彼! 看來咱的道行還不夠,這么重要的文檔竟然從來都不知道它的存在。
仔細閱讀一下居然發現還有不少Qt中和moc相關的編程限制需要我們注意, 各位看官也來受受再教育吧:
moc的功能數一數
- 處理Q_OBJECT宏和signals/slots關鍵字,生成信號和槽的底層代碼
- 處理Q_PROPERTY()和Q_ENUM()生成property系統代碼
- 處理Q_FLAGS()和Q_CLASSINFO()生成額外的類meta信息
不需要moc處理的代碼可以用預定義的宏括起來,如下:
#ifndef Q_MOC_RUN
…
#endif
moc的限制數一數(太多了,眼花繚亂)
- 模板類不能使用信號/槽機制
- moc不擴展宏,所以信號和槽的定義不能使用宏, 包括connect的時候也不能用宏做信號和槽的名字以及參數
- 從多個類派生時,QObject派生類必須放在第一個, 因為moc是這么認為的…(比較流氓) 這也是我們前面的例子觸犯的天條
- 函數指針不能作為信號或槽的參數, 因為其格式比較復雜,moc處理不了。 但可以用typedef把它定義成簡單的形式再使用。(這招可真夠絕的)
- 用枚舉類型或typedef的類型做信號和槽的參數時,必須fully qualified。 這個詞中文不知道怎么翻譯才合適,簡單的說就是, 如果是在類里定義的, 必須把類的路徑或者命名空間的路徑都加上, 防止出現混淆。 如Qt::Alignment之類的,前面的Qt就是Alignment的qualifier, 必須加上,而且有幾級加幾級。
- 信號和槽不能返回引用類型
- signals和slots關鍵字區域只能放置信號和槽的定義,不能放其它的如變量定義等
- 呵呵,這些限制條款感覺頗像不平等條約, 是不是讓你大開眼界了呢? 其實這些限制有一部分應該當作bug來論處, 只是對Qt編程影響不算太大,可暫時忽略,所以被歸入優先級很低的問題處理了(意思就是可能永遠都不改了)。